]> git.lyx.org Git - lyx.git/blobdiff - src/Text3.cpp
Add a pending space after math if it is not the last of the selection. This fixes...
[lyx.git] / src / Text3.cpp
index 2a5ebfc5737547e1bda398fce3101e86ba8f8041..18ec4777ede673c72ab0bc88d36b403d575ccfb9 100644 (file)
@@ -1,14 +1,14 @@
 /**
- * \file text3.cpp
+ * \file Text3.cpp
  * This file is part of LyX, the document processor.
  * Licence details can be found in the file COPYING.
  *
  * \author Asger Alstrup
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
  * \author Alfredo Braunstein
  * \author Angus Leeming
  * \author John Levon
- * \author André Pönitz
+ * \author André Pönitz
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -25,6 +25,7 @@
 #include "buffer_funcs.h"
 #include "BufferParams.h"
 #include "BufferView.h"
+#include "Changes.h"
 #include "Cursor.h"
 #include "CutAndPaste.h"
 #include "DispatchResult.h"
 #include "TextMetrics.h"
 #include "VSpace.h"
 
+#include "frontends/Application.h"
 #include "frontends/Clipboard.h"
+#include "frontends/LyXView.h"
 #include "frontends/Selection.h"
+#include "frontends/WorkArea.h"
 
 #include "insets/InsetCollapsable.h"
 #include "insets/InsetCommand.h"
+#include "insets/InsetExternal.h"
+#include "insets/InsetFloat.h"
 #include "insets/InsetFloatList.h"
+#include "insets/InsetGraphics.h"
+#include "insets/InsetGraphicsParams.h"
 #include "insets/InsetNewline.h"
 #include "insets/InsetQuotes.h"
 #include "insets/InsetSpecialChar.h"
 #include "insets/InsetText.h"
-#include "insets/InsetGraphics.h"
-#include "insets/InsetGraphicsParams.h"
+#include "insets/InsetWrap.h"
 
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/gettext.h"
 #include "support/lstrings.h"
 #include "support/lyxtime.h"
+#include "support/os.h"
 
 #include "mathed/InsetMathHull.h"
 #include "mathed/MathMacroTemplate.h"
@@ -84,6 +92,8 @@ using cap::pasteFromStack;
 using cap::pasteClipboardText;
 using cap::pasteClipboardGraphics;
 using cap::replaceSelection;
+using cap::grabAndEraseSelection;
+using cap::selClearOrDel;
 
 // globals...
 static Font freefont(ignore_font, ignore_language);
@@ -163,13 +173,11 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display)
                        istringstream is(selstr);
                        Lexer lex;
                        lex.setStream(is);
-                       formula->readQuiet(lex);
-                       if (formula->getType() == hullNone) {
+                       if (!formula->readQuiet(lex)) {
                                // No valid formula, let's try with delims
                                is.str("$" + selstr + "$");
                                lex.setStream(is);
-                               formula->readQuiet(lex);
-                               if (formula->getType() == hullNone) {
+                               if (!formula->readQuiet(lex)) {
                                        // Still not valid, leave it as is
                                        valid = false;
                                        delete formula;
@@ -189,6 +197,26 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display)
 }
 
 
+void regexpDispatch(Cursor & cur, FuncRequest const & cmd)
+{
+       BOOST_ASSERT(cmd.action == LFUN_REGEXP_MODE);
+       if (cur.inRegexped()) {
+               cur.message(_("Already in regexp mode"));
+               return;
+       }
+       cur.recordUndo();
+       docstring const save_selection = grabAndEraseSelection(cur);
+       selClearOrDel(cur);
+       // replaceSelection(cur);
+
+       cur.insert(new InsetMathHull(hullRegexp));
+       cur.nextInset()->edit(cur, true);
+       cur.niceInsert(save_selection);
+
+       cur.message(_("Regexp editor mode"));
+}
+
+
 static void specialChar(Cursor & cur, InsetSpecialChar::Kind kind)
 {
        cur.recordUndo();
@@ -208,7 +236,7 @@ static bool doInsertInset(Cursor & cur, Text * text,
                return false;
 
        if (InsetCollapsable * ci = inset->asInsetCollapsable())
-               ci->setLayout(bparams);
+               ci->setButtonLabel();
 
        cur.recordUndo();
        if (cmd.action == LFUN_INDEX_INSERT) {
@@ -217,7 +245,8 @@ static bool doInsertInset(Cursor & cur, Text * text,
                if (edit)
                        inset->edit(cur, true);
                // Now put this into inset
-               static_cast<InsetCollapsable *>(inset)->text().insertStringAsParagraphs(cur, ds);
+               cur.text()->insertStringAsLines(cur, ds);
+               cur.leaveInset(*inset);
                return true;
        }
 
@@ -235,8 +264,8 @@ static bool doInsertInset(Cursor & cur, Text * text,
        if (!gotsel || !pastesel)
                return true;
 
-       pasteFromStack(cur, cur.buffer().errorList("Paste"), 0);
-       cur.buffer().errors("Paste");
+       pasteFromStack(cur, cur.buffer()->errorList("Paste"), 0);
+       cur.buffer()->errors("Paste");
        cur.clearSelection(); // bug 393
        cur.finishUndo();
        InsetText * insetText = dynamic_cast<InsetText *>(inset);
@@ -270,6 +299,59 @@ string const freefont2string()
 }
 
 
+static void dragMove(Cursor & cur, int moveid, int movetoid)
+{
+       // Create pointers to buffers
+       Buffer & buf_move = *cur.buffer();
+       DocIterator dit_move = buf_move.getParFromID(moveid);
+       DocIterator dit_dest = buf_move.getParFromID(movetoid);
+
+       pit_type & pit_move = dit_move.pit();
+       pit_type & pit_dest = dit_dest.pit();
+       ParagraphList & pars = dit_move.text()->paragraphs();
+
+       // Create references to the paragraphs to be moved
+       ParagraphList::iterator const bgn = pars.begin();
+       ParagraphList::iterator dest_start = boost::next(bgn, pit_dest);
+
+       // The first paragraph of the area to be copied:
+       ParagraphList::iterator start = boost::next(bgn, pit_move);
+       // The final paragraph of area to be copied:
+       ParagraphList::iterator finish = start;
+       ParagraphList::iterator const end = pars.end();
+
+       // Move out (down) from this section header
+       if (finish != end)
+               ++finish;
+
+       // Seek the one (on same level) below
+       int const thistoclevel = start->layout().toclevel;
+       for (; finish != end; ++finish) {
+               int const toclevel = finish->layout().toclevel;
+               if (toclevel != Layout::NOT_IN_TOC
+                   && toclevel <= thistoclevel)
+                       break;
+       }
+
+       if (start == pars.begin() || start == dest_start)
+               // Nothing to move
+               return;
+
+       pars.insert(dest_start, start, finish);
+       pars.erase(start, finish);
+
+       // FIXME: This only really needs doing for the newly
+       // introduced paragraphs. Something like:
+       //      pit_type const numpars = distance(start, finish);
+       //      start = boost::next(bgn, pit);
+       //      finish = boost::next(start, numpars);
+       //      for (; start != finish; ++start)
+       //              start->setBuffer(buf);
+       // But while this seems to work, it is kind of fragile.
+       buf_move.inset().setBuffer(buf_move);
+}
+
+
 /// the type of outline operation
 enum OutlineOp {
        OutlineUp, // Move this header with text down
@@ -281,15 +363,15 @@ enum OutlineOp {
 
 static void outline(OutlineOp mode, Cursor & cur)
 {
-       Buffer & buf = cur.buffer();
+       Buffer & buf = *cur.buffer();
        pit_type & pit = cur.pit();
        ParagraphList & pars = buf.text().paragraphs();
-       ParagraphList::iterator bgn = pars.begin();
+       ParagraphList::iterator const bgn = pars.begin();
        // The first paragraph of the area to be copied:
        ParagraphList::iterator start = boost::next(bgn, pit);
        // The final paragraph of area to be copied:
        ParagraphList::iterator finish = start;
-       ParagraphList::iterator end = pars.end();
+       ParagraphList::iterator const end = pars.end();
 
        DocumentClass const & tc = buf.params().documentClass();
 
@@ -299,14 +381,18 @@ static void outline(OutlineOp mode, Cursor & cur)
        // 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) {
+               if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel)
                        break;
-               }
        }
 
+       // Do we need to set insets' buffer_ members, because we copied
+       // some stuff? We'll assume we do and reset it otherwise.
+       bool set_buffers = true;
+
        switch (mode) {
                case OutlineUp: {
                        if (start == pars.begin())
@@ -334,7 +420,7 @@ static void outline(OutlineOp mode, Cursor & cur)
                        start = boost::next(pars.begin(), deletepit);
                        pit = newpit;
                        pars.erase(start, finish);
-                       return;
+                       break;
                }
                case OutlineDown: {
                        if (finish == end)
@@ -346,9 +432,8 @@ static void outline(OutlineOp mode, Cursor & cur)
                        for (; dest != end; ++dest) {
                                toclevel = dest->layout().toclevel;
                                if (toclevel != Layout::NOT_IN_TOC
-                                   && toclevel <= thistoclevel) {
+                                     && toclevel <= thistoclevel)
                                        break;
-                               }
                        }
                        // One such was found:
                        pit_type newpit = distance(bgn, dest);
@@ -358,7 +443,7 @@ static void outline(OutlineOp mode, Cursor & cur)
                        start = boost::next(bgn, pit);
                        pit = newpit - len;
                        pars.erase(start, finish);
-                       return;
+                       break;
                }
                case OutlineIn: {
                        pit_type const len = distance(start, finish);
@@ -377,7 +462,8 @@ static void outline(OutlineOp mode, Cursor & cur)
                                        }
                                }
                        }
-                       return;
+                       set_buffers = false;
+                       break;
                }
                case OutlineOut: {
                        pit_type const len = distance(start, finish);
@@ -396,9 +482,20 @@ static void outline(OutlineOp mode, Cursor & cur)
                                        }
                                }
                        }
-                       return;
+                       set_buffers = false;
+                       break;
                }
        }
+       if (set_buffers)
+               // FIXME This only really needs doing for the newly introduced 
+               // paragraphs. Something like:
+               //      pit_type const numpars = distance(start, finish);
+               //      start = boost::next(bgn, pit);
+               //      finish = boost::next(start, numpars);
+               //      for (; start != finish; ++start)
+               //              start->setBuffer(buf);
+               // But while this seems to work, it is kind of fragile.
+               buf.inset().setBuffer(buf);
 }
 
 
@@ -420,10 +517,19 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 {
        LYXERR(Debug::ACTION, "Text::dispatch: cmd: " << cmd);
 
+       // Dispatch if the cursor is inside the text. It is not the
+       // case for context menus (bug 5797).
+       if (cur.text() != this) {
+               cur.undispatched();
+               return;
+       }
+
        BufferView * bv = &cur.bv();
-       TextMetrics & tm = bv->textMetrics(this);
-       if (!tm.contains(cur.pit()))
-               lyx::dispatch(FuncRequest(LFUN_SCREEN_RECENTER));
+       TextMetrics * tm = &bv->textMetrics(this);
+       if (!tm->contains(cur.pit())) {
+               lyx::dispatch(FuncRequest(LFUN_SCREEN_SHOW_CURSOR));
+               tm = &bv->textMetrics(this);
+       }
 
        // 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
@@ -449,7 +555,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                recUndo(cur, pit, pit + 1);
                cur.finishUndo();
                swap(pars_[pit], pars_[pit + 1]);
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                needsUpdate = true;
                ++cur.pit();
                break;
@@ -460,7 +566,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                recUndo(cur, pit - 1, pit);
                cur.finishUndo();
                swap(pars_[pit], pars_[pit - 1]);
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                --cur.pit();
                needsUpdate = true;
                break;
@@ -486,53 +592,71 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                par.params().startOfAppendix(start);
 
                // we can set the refreshing parameters now
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                break;
        }
 
        case LFUN_WORD_DELETE_FORWARD:
-               if (cur.selection()) {
+               if (cur.selection())
                        cutSelection(cur, true, false);
-               else
+               else
                        deleteWordForward(cur);
                finishChange(cur, false);
                break;
 
        case LFUN_WORD_DELETE_BACKWARD:
-               if (cur.selection()) {
+               if (cur.selection())
                        cutSelection(cur, true, false);
-               else
+               else
                        deleteWordBackward(cur);
                finishChange(cur, false);
                break;
 
        case LFUN_LINE_DELETE:
-               if (cur.selection()) {
+               if (cur.selection())
                        cutSelection(cur, true, false);
-               else
-                       tm.deleteLineForward(cur);
+               else
+                       tm->deleteLineForward(cur);
                finishChange(cur, false);
                break;
 
        case LFUN_BUFFER_BEGIN:
        case LFUN_BUFFER_BEGIN_SELECT:
                needsUpdate |= cur.selHandle(cmd.action == LFUN_BUFFER_BEGIN_SELECT);
-               if (cur.depth() == 1) {
+               if (cur.depth() == 1)
                        needsUpdate |= cursorTop(cur);
-               } else {
+               else
                        cur.undispatched();
-               }
                cur.updateFlags(Update::FitCursor);
                break;
 
        case LFUN_BUFFER_END:
        case LFUN_BUFFER_END_SELECT:
                needsUpdate |= cur.selHandle(cmd.action == LFUN_BUFFER_END_SELECT);
-               if (cur.depth() == 1) {
+               if (cur.depth() == 1)
                        needsUpdate |= cursorBottom(cur);
-               } else {
+               else
+                       cur.undispatched();
+               cur.updateFlags(Update::FitCursor);
+               break;
+
+       case LFUN_INSET_BEGIN:
+       case LFUN_INSET_BEGIN_SELECT:
+               needsUpdate |= cur.selHandle(cmd.action == LFUN_INSET_BEGIN_SELECT);
+               if (cur.depth() == 1 || cur.pos() > 0)
+                       needsUpdate |= cursorTop(cur);
+               else
+                       cur.undispatched();
+               cur.updateFlags(Update::FitCursor);
+               break;
+
+       case LFUN_INSET_END:
+       case LFUN_INSET_END_SELECT:
+               needsUpdate |= cur.selHandle(cmd.action == LFUN_INSET_END_SELECT);
+               if (cur.depth() == 1 || cur.pos() < cur.lastpos())
+                       needsUpdate |= cursorBottom(cur);
+               else
                        cur.undispatched();
-               }
                cur.updateFlags(Update::FitCursor);
                break;
 
@@ -546,6 +670,19 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                && cur.boundary() == oldBoundary) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_FORWARD);
+               
+                       // we will probably be moving out the inset, so we should execute
+                       // the depm-mechanism, but only when the cursor has a place to 
+                       // go outside this inset, i.e. in a slice above.
+                       if (cur.depth() > 1 && cur.pos() == cur.lastpos() 
+                                 && cur.pit() == cur.lastpit()) {
+                               // The cursor hasn't changed yet. To give the 
+                               // DEPM the possibility of doing something we must
+                               // provide it with two different cursors.
+                               Cursor dummy = cur;
+                               dummy.pos() = dummy.pit() = 0;
+                               cur.bv().checkDepm(dummy, cur);
+                       }
                }
                break;
 
@@ -559,6 +696,19 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        && cur.boundary() == oldBoundary) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
+
+                       // we will probably be moving out the inset, so we should execute
+                       // the depm-mechanism, but only when the cursor has a place to 
+                       // go outside this inset, i.e. in a slice above.
+                       if (cur.depth() > 1 && cur.pos() == 0 && cur.pit() == 0) {
+                               // The cursor hasn't changed yet. To give the 
+                               // DEPM the possibility of doing something we must
+                               // provide it with two different cursors.
+                               Cursor dummy = cur;
+                               dummy.pos() = cur.lastpos();
+                               dummy.pit() = cur.lastpit();
+                               cur.bv().checkDepm(dummy, cur);
+                       }
                }
                break;
 
@@ -616,16 +766,24 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                // stop/start the selection
                bool select = cmd.action == LFUN_DOWN_SELECT ||
                        cmd.action == LFUN_UP_SELECT;
-               cur.selHandle(select);
 
                // move cursor up/down
                bool up = cmd.action == LFUN_UP_SELECT || cmd.action == LFUN_UP;
-               bool const successful = cur.upDownInText(up, needsUpdate);
-               if (successful) {
-                       // redraw if you leave mathed (for the decorations)
+               bool const atFirstOrLastRow = cur.atFirstOrLastRow(up);
+
+               if (!atFirstOrLastRow) {
+                       needsUpdate |= cur.selHandle(select);   
+                       cur.selHandle(select);
+                       cur.upDownInText(up, needsUpdate);
                        needsUpdate |= cur.beforeDispatchCursor().inMathed();
-               } else
+               } else {
+                       // if the cursor cannot be moved up or down do not remove
+                       // the selection right now, but wait for the next dispatch.
+                       if (select)
+                               needsUpdate |= cur.selHandle(select);   
+                       cur.upDownInText(up, needsUpdate);
                        cur.undispatched();
+               }
 
                break;
        }
@@ -645,14 +803,49 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_LINE_BEGIN:
        case LFUN_LINE_BEGIN_SELECT:
                needsUpdate |= cur.selHandle(cmd.action == LFUN_LINE_BEGIN_SELECT);
-               needsUpdate |= tm.cursorHome(cur);
+               needsUpdate |= tm->cursorHome(cur);
                break;
 
        case LFUN_LINE_END:
        case LFUN_LINE_END_SELECT:
                needsUpdate |= cur.selHandle(cmd.action == LFUN_LINE_END_SELECT);
-               needsUpdate |= tm.cursorEnd(cur);
+               needsUpdate |= tm->cursorEnd(cur);
+               break;
+
+       case LFUN_SECTION_SELECT: {
+               Buffer const & buf = *cur.buffer();
+               pit_type const pit = cur.pit();
+               ParagraphList & pars = buf.text().paragraphs();
+               ParagraphList::iterator bgn = pars.begin();
+               // The first paragraph of the area to be selected:
+               ParagraphList::iterator start = boost::next(bgn, pit);
+               // The final paragraph of area to be selected:
+               ParagraphList::iterator finish = start;
+               ParagraphList::iterator end = pars.end();
+
+               int const thistoclevel = start->layout().toclevel;
+               if (thistoclevel == Layout::NOT_IN_TOC)
+                       break;
+
+               cur.pos() = 0;
+               Cursor const old_cur = cur;
+               needsUpdate |= cur.selHandle(true);
+
+               // Move out (down) from this section header
+               if (finish != end)
+                       ++finish;
+
+               // Seek the one (on same level) below
+               for (; finish != end; ++finish, ++cur.pit()) {
+                       int const toclevel = finish->layout().toclevel;
+                       if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel)
+                               break;
+               }
+               cur.pos() = cur.lastpos();
+               
+               needsUpdate |= cur != old_cur;
                break;
+       }
 
        case LFUN_WORD_RIGHT:
        case LFUN_WORD_RIGHT_SELECT:
@@ -736,6 +929,91 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
+       case LFUN_TAB_INSERT: {
+               bool const multi_par_selection = cur.selection() &&
+                       cur.selBegin().pit() != cur.selEnd().pit();
+               if (multi_par_selection) {
+                       // If there is a multi-paragraph selection, a tab is inserted
+                       // at the beginning of each paragraph.
+                       cur.recordUndoSelection();
+                       pit_type const pit_end = cur.selEnd().pit();
+                       for (pit_type pit = cur.selBegin().pit(); pit <= pit_end; pit++) {
+                               pars_[pit].insertChar(0, '\t', 
+                                                     bv->buffer().params().trackChanges);
+                               // Update the selection pos to make sure the selection does not
+                               // change as the inserted tab will increase the logical pos.
+                               if (cur.anchor_.pit() == pit)
+                                       cur.anchor_.forwardPos();
+                               if (cur.pit() == pit)
+                                       cur.forwardPos();
+                       }
+                       cur.finishUndo();
+               } else {
+                       // Maybe we shouldn't allow tabs within a line, because they
+                       // are not (yet) aligned as one might do expect.
+                       FuncRequest cmd(LFUN_SELF_INSERT, from_ascii("\t"));
+                       dispatch(cur, cmd);     
+               }
+               break;
+       }
+
+       case LFUN_TAB_DELETE: {
+               bool const tc = bv->buffer().params().trackChanges;
+               if (cur.selection()) {
+                       // If there is a selection, a tab (if present) is removed from
+                       // the beginning of each paragraph.
+                       cur.recordUndoSelection();
+                       pit_type const pit_end = cur.selEnd().pit();
+                       for (pit_type pit = cur.selBegin().pit(); pit <= pit_end; pit++) {
+                               Paragraph & par = paragraphs()[pit];
+                               if (par.getChar(0) == '\t') {
+                                       if (cur.pit() == pit)
+                                               cur.posBackward();
+                                       if (cur.anchor_.pit() == pit && cur.anchor_.pos() > 0 )
+                                               cur.anchor_.backwardPos();
+                                       
+                                       par.eraseChar(0, tc);
+                               } else 
+                                       // If no tab was present, try to remove up to four spaces.
+                                       for (int n_spaces = 0;
+                                            par.getChar(0) == ' ' && n_spaces < 4; ++n_spaces) {
+                                               if (cur.pit() == pit)
+                                                       cur.posBackward();
+                                               if (cur.anchor_.pit() == pit && cur.anchor_.pos() > 0 )
+                                                       cur.anchor_.backwardPos();
+                                               
+                                               par.eraseChar(0, tc);
+                                       }
+                       }
+                       cur.finishUndo();
+               } else {
+                       // If there is no selection, try to remove a tab or some spaces 
+                       // before the position of the cursor.
+                       Paragraph & par = paragraphs()[cur.pit()];
+                       pos_type const pos = cur.pos();
+                       
+                       if (pos == 0)
+                               break;
+                       
+                       char_type const c = par.getChar(pos - 1);
+                       cur.recordUndo();
+                       if (c == '\t') {
+                               cur.posBackward();
+                               par.eraseChar(cur.pos(), tc);
+                       } else
+                               for (int n_spaces = 0; 
+                                    cur.pos() > 0
+                                            && par.getChar(cur.pos() - 1) == ' ' 
+                                            && n_spaces < 4;
+                                    ++n_spaces) {
+                                       cur.posBackward();
+                                       par.eraseChar(cur.pos(), tc);
+                               }
+                       cur.finishUndo();
+               }
+               break;
+       }
+
        case LFUN_CHAR_DELETE_FORWARD:
                if (!cur.selection()) {
                        if (cur.pos() == cur.paragraph().size())
@@ -775,52 +1053,16 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                cur.resetAnchor();
                break;
 
-       // TODO
-       // With the creation of LFUN_PARAGRAPH_PARAMS, this is now redundant,
-       // as its duties can be performed there. Should it be removed??
-       // FIXME For now, it can just dispatch LFUN_PARAGRAPH_PARAMS...
-       case LFUN_PARAGRAPH_SPACING: {
-               Paragraph & par = cur.paragraph();
-               Spacing::Space cur_spacing = par.params().spacing().getSpace();
-               string cur_value = "1.0";
-               if (cur_spacing == Spacing::Other)
-                       cur_value = par.params().spacing().getValueAsString();
-
-               istringstream is(to_utf8(cmd.argument()));
-               string tmp;
-               is >> tmp;
-               Spacing::Space new_spacing = cur_spacing;
-               string new_value = cur_value;
-               if (tmp.empty()) {
-                       lyxerr << "Missing argument to `paragraph-spacing'"
-                              << endl;
-               } else if (tmp == "single") {
-                       new_spacing = Spacing::Single;
-               } else if (tmp == "onehalf") {
-                       new_spacing = Spacing::Onehalf;
-               } else if (tmp == "double") {
-                       new_spacing = Spacing::Double;
-               } else if (tmp == "other") {
-                       new_spacing = Spacing::Other;
-                       string tmpval = "0.0";
-                       is >> tmpval;
-                       lyxerr << "new_value = " << tmpval << endl;
-                       if (tmpval != "0.0")
-                               new_value = tmpval;
-               } else if (tmp == "default") {
-                       new_spacing = Spacing::Default;
-               } else {
-                       lyxerr << to_utf8(_("Unknown spacing argument: "))
-                              << to_utf8(cmd.argument()) << endl;
-               }
-               if (cur_spacing != new_spacing || cur_value != new_value)
-                       par.params().spacing(Spacing(new_spacing, new_value));
-               break;
-       }
-
        case LFUN_INSET_INSERT: {
                cur.recordUndo();
+
+               // We have to avoid triggering InstantPreview loading
+               // before inserting into the document. See bug #5626.
+               bool loaded = bv->buffer().isFullyLoaded();
+               bv->buffer().setFullyLoaded(false);
                Inset * inset = createInset(bv->buffer(), cmd);
+               bv->buffer().setFullyLoaded(loaded);
+
                if (inset) {
                        // FIXME (Abdel 01/02/2006):
                        // What follows would be a partial fix for bug 2154:
@@ -848,29 +1090,39 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                cutSelection(cur, true, false);
                        cur.insert(inset);
                        cur.posForward();
+
+                       // trigger InstantPreview now
+                       if (inset->lyxCode() == EXTERNAL_CODE) {
+                               InsetExternal & ins =
+                                       static_cast<InsetExternal &>(*inset);
+                               ins.updatePreview();
+                       }
                }
-               break;
-       }
 
-       case LFUN_INSET_DISSOLVE:
-               needsUpdate |= dissolveInset(cur);
                break;
+       }
 
-       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;
+       case LFUN_INSET_DISSOLVE: {
+               // first, try if there's an inset at cursor
+               // FIXME: this first part should be moved to
+               // a LFUN_NEXT_INSET_DISSOLVE, or be called via
+               // some generic "next-inset inset-dissolve"
+               Inset * inset = cur.nextInset();
+               if (inset && inset->isActive()) {
+                       Cursor tmpcur = cur;
+                       tmpcur.pushBackward(*inset);
+                       inset->dispatch(tmpcur, cmd);
+                       if (tmpcur.result().dispatched()) {
+                               cur.dispatched();
+                               break;
+                       }
                }
-               // else, if there is an inset at the cursor, access this
-               Inset * next_inset = cur.nextInset();
-               if (next_inset) {
-                       next_inset->showInsetDialog(bv);
+               // if it did not work, try the underlying inset
+               if (dissolveInset(cur)) {
+                       needsUpdate = true;
                        break;
                }
-               // if not then access the underlying inset.
-               inset.showInsetDialog(bv);
+               // if it did not work, do nothing.
                break;
        }
 
@@ -955,7 +1207,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (arg.empty()) {
                        if (theClipboard().isInternal())
                                pasteFromStack(cur, bv->buffer().errorList("Paste"), 0);
-                       else if (theClipboard().hasGraphicsContents())
+                       else if (theClipboard().hasGraphicsContents() 
+                                    && !theClipboard().hasTextContents())
                                pasteClipboardGraphics(cur, bv->buffer().errorList("Paste"));
                        else
                                pasteClipboardText(cur, bv->buffer().errorList("Paste"));
@@ -973,6 +1226,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                type = Clipboard::JpegGraphicsType;
                        else if (arg == "linkback")
                                type = Clipboard::LinkBackGraphicsType;
+                       else if (arg == "emf")
+                               type = Clipboard::EmfGraphicsType;
+                       else if (arg == "wmf")
+                               type = Clipboard::WmfGraphicsType;
+
                        else
                                LASSERT(false, /**/);
 
@@ -997,8 +1255,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_SERVER_GET_XY:
                cur.message(from_utf8(
-                       convert<string>(tm.cursorX(cur.top(), cur.boundary()))
-                       + ' ' + convert<string>(tm.cursorY(cur.top(), cur.boundary()))));
+                       convert<string>(tm->cursorX(cur.top(), cur.boundary()))
+                       + ' ' + convert<string>(tm->cursorY(cur.top(), cur.boundary()))));
                break;
 
        case LFUN_SERVER_SET_XY: {
@@ -1010,7 +1268,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        lyxerr << "SETXY: Could not parse coordinates in '"
                               << to_utf8(cmd.argument()) << endl;
                else
-                       tm.setCursorFromCoordinates(cur, x, y);
+                       tm->setCursorFromCoordinates(cur, x, y);
                break;
        }
 
@@ -1091,6 +1349,15 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                            cmd.argument() == "paragraph");
                break;
 
+       case LFUN_SELECTION_PASTE:
+               // 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");
+               break;
+
        case LFUN_UNICODE_INSERT: {
                if (cmd.argument().empty())
                        break;
@@ -1111,7 +1378,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                pos_type pos = cur.pos();
                BufferParams const & bufparams = bv->buffer().params();
                Layout const & style = par.layout();
-               if (!style.pass_thru
+               InsetLayout const & ilayout = cur.inset().getLayout();
+               if (!style.pass_thru && !ilayout.isPassThru()
                    && par.getFontSettings(bufparams, pos).language()->lang() != "hebrew") {
                        // this avoids a double undo
                        // FIXME: should not be needed, ideally
@@ -1146,9 +1414,9 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_MOUSE_TRIPLE:
                if (cmd.button() == mouse_button::button1) {
-                       tm.cursorHome(cur);
+                       tm->cursorHome(cur);
                        cur.resetAnchor();
-                       tm.cursorEnd(cur);
+                       tm->cursorEnd(cur);
                        cur.setSelection();
                        bv->cursor() = cur;
                }
@@ -1175,23 +1443,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                case mouse_button::button2:
                        // Middle mouse pasting.
                        bv->mouseSetCursor(cur);
-                       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;
-                       }
-                       // 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();
+                       lyx::dispatch(
+                               FuncRequest(LFUN_COMMAND_ALTERNATIVES,
+                                           "selection-paste ; primary-selection-paste paragraph"));
+                       cur.noUpdate();
                        break;
 
                case mouse_button::button3: {
@@ -1230,7 +1485,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                int const wh = bv->workHeight();
                int const y = max(0, min(wh - 1, cmd.y));
 
-               tm.setCursorFromCoordinates(cur, cmd.x, y);
+               tm->setCursorFromCoordinates(cur, cmd.x, y);
                cur.setTargetX(cmd.x);
                if (cmd.y >= wh)
                        lyx::dispatch(FuncRequest(LFUN_DOWN_SELECT));
@@ -1320,6 +1575,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
                cur.resetAnchor();
                moveCursor(cur, false);
+               bv->bookmarkEditPosition();
                break;
        }
 
@@ -1372,6 +1628,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                }
                if (!inset)
                        break;
+               cur.recordUndo();
                insertInset(cur, inset);
                cur.posForward();
                break;
@@ -1382,6 +1639,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_FLEX_INSERT:
        case LFUN_BOX_INSERT:
        case LFUN_BRANCH_INSERT:
+       case LFUN_PHANTOM_INSERT:
        case LFUN_ERT_INSERT:
        case LFUN_LISTING_INSERT:
        case LFUN_MARGINALNOTE_INSERT:
@@ -1393,7 +1651,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                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());
+               bv->buffer().updateLabels();
                break;
 
        case LFUN_TABULAR_INSERT:
@@ -1408,10 +1666,18 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_FLOAT_INSERT:
        case LFUN_FLOAT_WIDE_INSERT:
        case LFUN_WRAP_INSERT: {
-               bool content = cur.selection();  // will some text be moved into the inset?
+               // will some text be moved into the inset?
+               bool content = cur.selection();
 
                doInsertInset(cur, this, cmd, true, true);
                cur.posForward();
+
+               // If some text is moved into the inset, doInsertInset 
+               // puts the cursor outside the inset. To insert the
+               // caption we put it back into the inset.
+               if (content)
+                       cur.backwardPos();
+
                ParagraphList & pars = cur.text()->paragraphs();
 
                DocumentClass const & tclass = bv->buffer().params().documentClass();
@@ -1438,7 +1704,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                // We cannot use Cursor::dispatch here it needs access to up to
                // date metrics.
                FuncRequest cmd_caption(LFUN_CAPTION_INSERT);
-               cur.text()->dispatch(cur, cmd_caption);
+               doInsertInset(cur, cur.text(), cmd_caption, true, false);
+               bv->buffer().updateLabels();
                cur.updateFlags(Update::Force);
                // FIXME: When leaving the Float (or Wrap) inset we should
                // delete any empty paragraph left above or below the
@@ -1457,7 +1724,18 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_INDEX_PRINT:
+       case LFUN_INDEX_PRINT: {
+               InsetCommandParams p(INDEX_PRINT_CODE);
+               if (cmd.argument().empty())
+                       p["type"] = from_ascii("idx");
+               else
+                       p["type"] = cmd.argument();
+               string const data = InsetCommand::params2string("index_print", p);
+               FuncRequest fr(LFUN_INSET_INSERT, data);
+               dispatch(cur, fr);
+               break;
+       }
+       
        case LFUN_NOMENCL_PRINT:
        case LFUN_TOC_INSERT:
        case LFUN_LINE_INSERT:
@@ -1479,6 +1757,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                mathDispatch(cur, cmd, true);
                break;
 
+       case LFUN_REGEXP_MODE:
+               regexpDispatch(cur, cmd);
+               break;
+
        case LFUN_MATH_MODE:
                if (cmd.argument() == "on")
                        // don't pass "on" as argument
@@ -1520,6 +1802,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_MATH_INSERT:
+       case LFUN_MATH_AMS_MATRIX:
        case LFUN_MATH_MATRIX:
        case LFUN_MATH_DELIM:
        case LFUN_MATH_BIGDELIM: {
@@ -1539,6 +1822,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
+       case LFUN_FONT_ITAL: {
+               Font font(ignore_font, ignore_language);
+               font.fontInfo().setShape(ITALIC_SHAPE);
+               toggleAndShow(cur, this, font);
+               break;
+       }
+
        case LFUN_FONT_BOLD:
        case LFUN_FONT_BOLDSYMBOL: {
                Font font(ignore_font, ignore_language);
@@ -1581,6 +1871,27 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
+       case LFUN_FONT_STRIKEOUT: {
+               Font font(ignore_font, ignore_language);
+               font.fontInfo().setStrikeout(FONT_TOGGLE);
+               toggleAndShow(cur, this, font);
+               break;
+       }
+
+       case LFUN_FONT_UULINE: {
+               Font font(ignore_font, ignore_language);
+               font.fontInfo().setUuline(FONT_TOGGLE);
+               toggleAndShow(cur, this, font);
+               break;
+       }
+
+       case LFUN_FONT_UWAVE: {
+               Font font(ignore_font, ignore_language);
+               font.fontInfo().setUwave(FONT_TOGGLE);
+               toggleAndShow(cur, this, font);
+               break;
+       }
+
        case LFUN_FONT_UNDERLINE: {
                Font font(ignore_font, ignore_language);
                font.fontInfo().setUnderbar(FONT_TOGGLE);
@@ -1753,6 +2064,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                // Get word or selection
                                selectWordWhenUnderCursor(cur, WHOLE_WORD);
                                arg = cur.selectionAsString(false);
+                               arg += " lang=" + from_ascii(cur.getFont().language()->lang());
                        }
                }
                bv->showDialog("thesaurus", to_utf8(arg));
@@ -1795,28 +2107,38 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_OUTLINE_UP:
                outline(OutlineUp, cur);
                setCursor(cur, cur.pit(), 0);
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                needsUpdate = true;
                break;
 
        case LFUN_OUTLINE_DOWN:
                outline(OutlineDown, cur);
                setCursor(cur, cur.pit(), 0);
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                needsUpdate = true;
                break;
 
        case LFUN_OUTLINE_IN:
                outline(OutlineIn, cur);
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                needsUpdate = true;
                break;
 
        case LFUN_OUTLINE_OUT:
                outline(OutlineOut, cur);
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                needsUpdate = true;
                break;
+       
+       case LFUN_OUTLINE_DRAGMOVE: {
+               int const move_id = convert<int>(cmd.getArg(0));
+               int const move_to_id = convert<int>(cmd.getArg(1));
+               dragMove(cur, move_id, move_to_id);
+               setCursor(cur, cur.pit(), 0);
+               cur.buffer()->updateLabels();
+               needsUpdate = true;
+               break;
+       }
 
        default:
                LYXERR(Debug::ACTION, "Command " << cmd << " not DISPATCHED by Text");
@@ -1824,6 +2146,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
+       if (lyxrc.spellcheck_continuously && cur.inTexted())
+               // Take this opportunity to spellcheck current word.
+               cur.paragraph().isMisspelled(cur.pos());
+
        needsUpdate |= (cur.pos() != cur.lastpos()) && cur.selection();
 
        // FIXME: The cursor flag is reset two lines below
@@ -1849,7 +2175,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        if (!needsUpdate
            && &oldTopSlice.inset() == &cur.inset()
            && oldTopSlice.idx() == cur.idx()
-           && !sel // sel is a backup of cur.selection() at the biginning of the function.
+           && !sel // sel is a backup of cur.selection() at the beginning of the function.
            && !cur.selection())
                // FIXME: it would be better if we could just do this
                //
@@ -1892,8 +2218,11 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_DIALOG_SHOW_NEW_INSET:
                if (cmd.argument() == "bibitem")
                        code = BIBITEM_CODE;
-               else if (cmd.argument() == "bibtex")
+               else if (cmd.argument() == "bibtex") {
                        code = BIBTEX_CODE;
+                       // not allowed in description items
+                       enable = !inDescriptionItem(cur);
+               }
                else if (cmd.argument() == "box")
                        code = BOX_CODE;
                else if (cmd.argument() == "branch")
@@ -1914,12 +2243,18 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                        code = INCLUDE_CODE;
                else if (cmd.argument() == "index")
                        code = INDEX_CODE;
+               else if (cmd.argument() == "index_print")
+                       code = INDEX_PRINT_CODE;
                else if (cmd.argument() == "nomenclature")
                        code = NOMENCL_CODE;
+               else if (cmd.argument() == "nomencl_print")
+                       code = NOMENCL_PRINT_CODE;
                else if (cmd.argument() == "label")
                        code = LABEL_CODE;
                else if (cmd.argument() == "note")
                        code = NOTE_CODE;
+               else if (cmd.argument() == "phantom")
+                       code = PHANTOM_CODE;
                else if (cmd.argument() == "ref")
                        code = REF_CODE;
                else if (cmd.argument() == "space")
@@ -1953,9 +2288,36 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                break;
        case LFUN_FLOAT_INSERT:
        case LFUN_FLOAT_WIDE_INSERT:
+               // FIXME: If there is a selection, we should check whether there
+               // are floats in the selection, but this has performance issues, see
+               // LFUN_CHANGE_ACCEPT/REJECT.
                code = FLOAT_CODE;
-               // not allowed in description items
-               enable = !inDescriptionItem(cur);
+               if (inDescriptionItem(cur))
+                       // not allowed in description items
+                       enable = false;
+               else {
+                       InsetCode const inset_code = cur.inset().lyxCode();
+
+                       // algorithm floats cannot be put in another float
+                       if (to_utf8(cmd.argument()) == "algorithm") {
+                               enable = inset_code != WRAP_CODE && inset_code != FLOAT_CODE;
+                               break;
+                       }
+
+                       // for figures and tables: only allow in another
+                       // float or wrap if it is of the same type and
+                       // not a subfloat already
+                       if(cur.inset().lyxCode() == code) {
+                               InsetFloat const & ins =
+                                       static_cast<InsetFloat const &>(cur.inset());
+                               enable = ins.params().type == to_utf8(cmd.argument())
+                                       && !ins.params().subfloat;
+                       } else if(cur.inset().lyxCode() == WRAP_CODE) {
+                               InsetWrap const & ins =
+                                       static_cast<InsetWrap const &>(cur.inset());
+                               enable = ins.params().type == to_utf8(cmd.argument());
+                       }
+               }
                break;
        case LFUN_WRAP_INSERT:
                code = WRAP_CODE;
@@ -1964,6 +2326,8 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                break;
        case LFUN_FLOAT_LIST_INSERT:
                code = FLOAT_LIST_CODE;
+               // not allowed in description items
+               enable = !inDescriptionItem(cur);
                break;
        case LFUN_CAPTION_INSERT:
                code = CAPTION_CODE;
@@ -1982,11 +2346,11 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                code = FLEX_CODE;
                string s = cmd.getArg(0);
                InsetLayout il =
-                       cur.buffer().params().documentClass().insetLayout(from_utf8(s));
-               if (il.lyxtype() != "charstyle" &&
-                   il.lyxtype() != "custom" &&
-                   il.lyxtype() != "element" &&
-                   il.lyxtype ()!= "standard")
+                       cur.buffer()->params().documentClass().insetLayout(from_utf8(s));
+               if (il.lyxtype() != InsetLayout::CHARSTYLE &&
+                   il.lyxtype() != InsetLayout::CUSTOM &&
+                   il.lyxtype() != InsetLayout::ELEMENT &&
+                   il.lyxtype ()!= InsetLayout::STANDARD)
                        enable = false;
                break;
                }
@@ -1995,12 +2359,19 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                break;
        case LFUN_BRANCH_INSERT:
                code = BRANCH_CODE;
-               if (cur.buffer().masterBuffer()->params().branchlist().empty())
+               if (cur.buffer()->masterBuffer()->params().branchlist().empty()
+                   && cur.buffer()->params().branchlist().empty())
                        enable = false;
                break;
+       case LFUN_PHANTOM_INSERT:
+               code = PHANTOM_CODE;
+               break;
        case LFUN_LABEL_INSERT:
                code = LABEL_CODE;
                break;
+       case LFUN_LINE_INSERT:
+               code = LINE_CODE;
+               break;
        case LFUN_INFO_INSERT:
                code = INFO_CODE;
                break;
@@ -2014,6 +2385,8 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                break;
        case LFUN_INDEX_PRINT:
                code = INDEX_PRINT_CODE;
+               // not allowed in description items
+               enable = !inDescriptionItem(cur);
                break;
        case LFUN_NOMENCL_INSERT:
                if (cur.selIsMultiCell() || cur.selIsMultiLine()) {
@@ -2024,9 +2397,13 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                break;
        case LFUN_NOMENCL_PRINT:
                code = NOMENCL_PRINT_CODE;
+               // not allowed in description items
+               enable = !inDescriptionItem(cur);
                break;
        case LFUN_TOC_INSERT:
                code = TOC_CODE;
+               // not allowed in description items
+               enable = !inDescriptionItem(cur);
                break;
        case LFUN_HYPERLINK_INSERT:
                if (cur.selIsMultiCell() || cur.selIsMultiLine()) {
@@ -2048,6 +2425,19 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                        code = SPACE_CODE;
                break;
 
+       case LFUN_MATH_INSERT:
+       case LFUN_MATH_AMS_MATRIX:
+       case LFUN_MATH_MATRIX:
+       case LFUN_MATH_DELIM:
+       case LFUN_MATH_BIGDELIM:
+       case LFUN_MATH_DISPLAY:
+       case LFUN_MATH_MODE:
+       case LFUN_MATH_MACRO:
+       case LFUN_MATH_SUBSCRIPT:
+       case LFUN_MATH_SUPERSCRIPT:
+               code = MATH_HULL_CODE;
+               break;
+
        case LFUN_INSET_MODIFY:
                // We need to disable this, because we may get called for a
                // tabular cell via
@@ -2060,6 +2450,10 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                flag.setOnOff(fontinfo.emph() == FONT_ON);
                break;
 
+       case LFUN_FONT_ITAL:
+               flag.setOnOff(fontinfo.shape() == ITALIC_SHAPE);
+               break;
+
        case LFUN_FONT_NOUN:
                flag.setOnOff(fontinfo.noun() == FONT_ON);
                break;
@@ -2105,11 +2499,14 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                }
 
                // 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;
+               Clipboard::GraphicsType type = Clipboard::AnyGraphicsType;
+               if ((arg == "pdf" && (type = Clipboard::PdfGraphicsType))
+                         || (arg == "png" && (type = Clipboard::PngGraphicsType))
+                         || (arg == "jpeg" && (type = Clipboard::JpegGraphicsType))
+                         || (arg == "linkback" &&  (type = Clipboard::LinkBackGraphicsType))
+                         || (arg == "emf" &&  (type = Clipboard::EmfGraphicsType))
+                         || (arg == "wmf" &&  (type = Clipboard::WmfGraphicsType))) {
+                       enable = theClipboard().hasGraphicsContents(type);
                        break;
                }
 
@@ -2126,6 +2523,10 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                enable = cur.selection() || !theSelection().empty();
                break;
 
+       case LFUN_SELECTION_PASTE:
+               enable = cap::selection();
+               break;
+
        case LFUN_PARAGRAPH_MOVE_UP:
                enable = cur.pit() > 0 && !cur.selection();
                break;
@@ -2136,30 +2537,40 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
 
        case LFUN_INSET_DISSOLVE:
                if (!cmd.argument().empty()) {
-                       InsetLayout il = cur.inset().getLayout(cur.buffer().params());
+                       InsetLayout const & il = cur.inset().getLayout();
+                       InsetLayout::InsetLyXType const type = 
+                                       translateLyXType(to_utf8(cmd.argument()));
                        enable = cur.inset().lyxCode() == FLEX_CODE
-                                && il.lyxtype() == to_utf8(cmd.argument());
+                                && il.lyxtype() == type;
                } else {
-                       enable = !isMainText(cur.bv().buffer())
-                                && cur.inset().nargs() == 1;
+                       enable = ((!isMainText(cur.bv().buffer())
+                                     && cur.inset().nargs() == 1)
+                                 || (cur.nextInset()
+                                     && cur.nextInset()->nargs() == 1));
                }
                break;
 
        case LFUN_CHANGE_ACCEPT:
        case LFUN_CHANGE_REJECT:
-               // TODO: context-sensitive enabling of LFUN_CHANGE_ACCEPT/REJECT
                // In principle, these LFUNs should only be enabled if there
                // is a change at the current position/in the current selection.
                // However, without proper optimizations, this will inevitably
                // result in unacceptable performance - just imagine a user who
                // wants to select the complete content of a long document.
-               enable = true;
+               if (!cur.selection()) {
+                       Change const & change = cur.paragraph().lookupChange(cur.pos());
+                       enable = change.changed();
+               } else
+                       // TODO: context-sensitive enabling of LFUN_CHANGE_ACCEPT/REJECT
+                       // for selections.
+                       enable = true;
                break;
 
        case LFUN_OUTLINE_UP:
        case LFUN_OUTLINE_DOWN:
        case LFUN_OUTLINE_IN:
        case LFUN_OUTLINE_OUT:
+       case LFUN_OUTLINE_DRAGMOVE:
                // FIXME: LyX is not ready for outlining within inset.
                enable = isMainText(cur.bv().buffer())
                        && cur.paragraph().layout().toclevel != Layout::NOT_IN_TOC;
@@ -2170,6 +2581,11 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                enable = (cur.pos() > cur.paragraph().beginOfBody());
                break;
 
+       case LFUN_TAB_INSERT:
+       case LFUN_TAB_DELETE:
+               enable = cur.inset().getLayout().isPassThru();
+               break;
+
        case LFUN_SET_GRAPHICS_GROUP: {
                InsetGraphics * ins = graphics::getCurrentGraphicsInset(cur);
                if (!ins)
@@ -2181,9 +2597,23 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
 
        case LFUN_NEWPAGE_INSERT:
                // not allowed in description items
+               code = NEWPAGE_CODE;
                enable = !inDescriptionItem(cur);
                break;
 
+       case LFUN_DATE_INSERT: {
+               string const format = cmd.argument().empty()
+                       ? lyxrc.date_insert_format : to_utf8(cmd.argument());
+               enable = support::os::is_valid_strftime(format);
+               break;
+       }
+
+       case LFUN_LANGUAGE:
+               enable = !cur.inset().getLayout().isPassThru();
+
+       case LFUN_BREAK_PARAGRAPH:
+               enable = cur.inset().getLayout().isMultiPar();
+
        case LFUN_WORD_DELETE_FORWARD:
        case LFUN_WORD_DELETE_BACKWARD:
        case LFUN_LINE_DELETE:
@@ -2212,14 +2642,13 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_WORD_RIGHT_SELECT:
        case LFUN_WORD_LEFT_SELECT:
        case LFUN_WORD_SELECT:
+       case LFUN_SECTION_SELECT:
        case LFUN_PARAGRAPH_UP:
        case LFUN_PARAGRAPH_DOWN:
        case LFUN_LINE_BEGIN:
        case LFUN_LINE_END:
        case LFUN_CHAR_DELETE_FORWARD:
        case LFUN_CHAR_DELETE_BACKWARD:
-       case LFUN_BREAK_PARAGRAPH:
-       case LFUN_PARAGRAPH_SPACING:
        case LFUN_INSET_INSERT:
        case LFUN_WORD_UPCASE:
        case LFUN_WORD_LOWCASE:
@@ -2229,22 +2658,13 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_SERVER_SET_XY:
        case LFUN_SERVER_GET_LAYOUT:
        case LFUN_LAYOUT:
-       case LFUN_DATE_INSERT:
        case LFUN_SELF_INSERT:
-       case LFUN_LINE_INSERT:
-       case LFUN_MATH_DISPLAY:
-       case LFUN_MATH_MODE:
-       case LFUN_MATH_MACRO:
-       case LFUN_MATH_MATRIX:
-       case LFUN_MATH_DELIM:
-       case LFUN_MATH_BIGDELIM:
-       case LFUN_MATH_INSERT:
-       case LFUN_MATH_SUBSCRIPT:
-       case LFUN_MATH_SUPERSCRIPT:
        case LFUN_FONT_DEFAULT:
        case LFUN_FONT_UNDERLINE:
+       case LFUN_FONT_STRIKEOUT:
+       case LFUN_FONT_UULINE:
+       case LFUN_FONT_UWAVE:
        case LFUN_FONT_SIZE:
-       case LFUN_LANGUAGE:
        case LFUN_TEXTSTYLE_APPLY:
        case LFUN_TEXTSTYLE_UPDATE:
        case LFUN_LAYOUT_PARAGRAPH:
@@ -2269,10 +2689,14 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_PARAGRAPH_PARAMS_APPLY:
        case LFUN_PARAGRAPH_PARAMS:
        case LFUN_ESCAPE:
-       case LFUN_BUFFER_END:
        case LFUN_BUFFER_BEGIN:
+       case LFUN_BUFFER_END:
        case LFUN_BUFFER_BEGIN_SELECT:
        case LFUN_BUFFER_END_SELECT:
+       case LFUN_INSET_BEGIN:
+       case LFUN_INSET_END:
+       case LFUN_INSET_BEGIN_SELECT:
+       case LFUN_INSET_END_SELECT:
        case LFUN_UNICODE_INSERT:
                // these are handled in our dispatch()
                enable = true;
@@ -2283,9 +2707,66 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        }
 
        if (code != NO_CODE
-           && (cur.empty() || !cur.inset().insetAllowed(code)))
+           && (cur.empty() 
+               || !cur.inset().insetAllowed(code)
+               || cur.paragraph().layout().pass_thru))
                enable = false;
 
+       switch (cmd.action) {
+       case LFUN_ACCENT_ACUTE:
+       case LFUN_ACCENT_BREVE:
+       case LFUN_ACCENT_CARON:
+       case LFUN_ACCENT_CEDILLA:
+       case LFUN_ACCENT_CIRCLE:
+       case LFUN_ACCENT_CIRCUMFLEX:
+       case LFUN_ACCENT_DOT:
+       case LFUN_ACCENT_GRAVE:
+       case LFUN_ACCENT_HUNGARIAN_UMLAUT:
+       case LFUN_ACCENT_MACRON:
+       case LFUN_ACCENT_OGONEK:
+       case LFUN_ACCENT_TIE:
+       case LFUN_ACCENT_TILDE:
+       case LFUN_ACCENT_UMLAUT:
+       case LFUN_ACCENT_UNDERBAR:
+       case LFUN_ACCENT_UNDERDOT:
+       case LFUN_APPENDIX:
+       case LFUN_DEPTH_DECREMENT:
+       case LFUN_DEPTH_INCREMENT:
+       case LFUN_FILE_INSERT:
+       case LFUN_FONT_BOLD:
+       case LFUN_FONT_BOLDSYMBOL:
+       case LFUN_FONT_TYPEWRITER:
+       case LFUN_FONT_DEFAULT:
+       case LFUN_FONT_EMPH:
+       case LFUN_FONT_NOUN:
+       case LFUN_FONT_ROMAN:
+       case LFUN_FONT_SANS:
+       case LFUN_FONT_FRAK:
+       case LFUN_FONT_ITAL:
+       case LFUN_FONT_SIZE:
+       case LFUN_FONT_STATE:
+       case LFUN_FONT_UNDERLINE:
+       case LFUN_FONT_STRIKEOUT:
+       case LFUN_FONT_UULINE:
+       case LFUN_FONT_UWAVE:
+       case LFUN_LABEL_GOTO:
+       case LFUN_LAYOUT_TABULAR:
+       case LFUN_MENU_OPEN:
+       case LFUN_NOACTION:
+       case LFUN_NOTE_NEXT:
+       case LFUN_REFERENCE_NEXT:
+       case LFUN_SERVER_GOTO_FILE_ROW:
+       case LFUN_SERVER_NOTIFY:
+       case LFUN_SERVER_SET_XY:
+       case LFUN_TEXTSTYLE_APPLY:
+       case LFUN_TEXTSTYLE_UPDATE:
+               if (cur.inset().getLayout().isPassThru())
+                       enable = false;
+               break;
+       default:
+               break;
+       }
+
        flag.setEnabled(enable);
        return true;
 }