]> git.lyx.org Git - lyx.git/blobdiff - src/Text3.cpp
avoid float-conversion warning and simplify size computation
[lyx.git] / src / Text3.cpp
index 286d5bb7dcbf512237d5f15ecd8e7a378c5c1d16..8707b76062d8c6569981cf00cc91cccc98cae628 100644 (file)
@@ -47,6 +47,7 @@
 #include "TextMetrics.h"
 #include "WordLangTuple.h"
 
+#include "frontends/alert.h"
 #include "frontends/Application.h"
 #include "frontends/Clipboard.h"
 #include "frontends/Selection.h"
@@ -71,6 +72,7 @@
 #include "support/gettext.h"
 #include "support/lassert.h"
 #include "support/lstrings.h"
+#include "support/lyxalgo.h"
 #include "support/lyxtime.h"
 #include "support/os.h"
 #include "support/regex.h"
@@ -78,8 +80,6 @@
 #include "mathed/InsetMathHull.h"
 #include "mathed/MathMacroTemplate.h"
 
-#include <boost/next_prior.hpp>
-
 #include <clocale>
 #include <sstream>
 
@@ -265,6 +265,42 @@ static bool doInsertInset(Cursor & cur, Text * text,
                }
                return true;
        }
+       else if (cmd.action() == LFUN_ARGUMENT_INSERT) {
+               bool cotextinsert = false;
+               InsetArgument const * const ia = static_cast<InsetArgument const *>(inset);
+               Layout const & lay = cur.paragraph().layout();
+               Layout::LaTeXArgMap args = lay.args();
+               Layout::LaTeXArgMap::const_iterator const lait = args.find(ia->name());
+               if (lait != args.end())
+                       cotextinsert = (*lait).second.insertcotext;
+               else {
+                       InsetLayout const & il = cur.inset().getLayout();
+                       args = il.args();
+                       Layout::LaTeXArgMap::const_iterator const ilait = args.find(ia->name());
+                       if (ilait != args.end())
+                               cotextinsert = (*ilait).second.insertcotext;
+               }
+               // The argument requests to insert a copy of the co-text to the inset
+               if (cotextinsert) {
+                       docstring ds;
+                       // If we have a selection within a paragraph, use this
+                       if (cur.selection() && cur.selBegin().pit() == cur.selEnd().pit())
+                               ds = cur.selectionAsString(false);
+                       // else use the whole paragraph
+                       else
+                               ds = cur.paragraph().asString();
+                       text->insertInset(cur, inset);
+                       if (edit)
+                               inset->edit(cur, true);
+                       // Now put co-text into inset
+                       Font const f(inherit_font, cur.current_font.language());
+                       if (!ds.empty()) {
+                               cur.text()->insertStringAsLines(cur, ds, f);
+                               cur.leaveInset(*inset);
+                       }
+                       return true;
+               }
+       }
 
        bool gotsel = false;
        if (cur.selection()) {
@@ -340,13 +376,11 @@ static void outline(OutlineOp mode, Cursor & cur)
        ParagraphList & pars = buf.text().paragraphs();
        ParagraphList::iterator const bgn = pars.begin();
        // The first paragraph of the area to be copied:
-       ParagraphList::iterator start = boost::next(bgn, pit);
+       ParagraphList::iterator start = next(bgn, pit);
        // The final paragraph of area to be copied:
        ParagraphList::iterator finish = start;
        ParagraphList::iterator const end = pars.end();
 
-       DocumentClass const & tc = buf.params().documentClass();
-
        int const thistoclevel = buf.text().getTocLevel(distance(bgn, start));
        int toclevel;
 
@@ -383,7 +417,7 @@ static void outline(OutlineOp mode, Cursor & cur)
                        pit_type const newpit = distance(bgn, dest);
                        pit_type const len = distance(start, finish);
                        pit_type const deletepit = pit + len;
-                       buf.undo().recordUndo(cur, ATOMIC_UNDO, newpit, deletepit - 1);
+                       buf.undo().recordUndo(cur, newpit, deletepit - 1);
                        pars.splice(dest, start, finish);
                        cur.pit() = newpit;
                        break;
@@ -393,7 +427,7 @@ static void outline(OutlineOp mode, Cursor & cur)
                                // Nothing to move.
                                return;
                        // Go one down from *this* header:
-                       ParagraphList::iterator dest = boost::next(finish, 1);
+                       ParagraphList::iterator dest = next(finish, 1);
                        // Go further down to find header to insert in front of:
                        for (; dest != end; ++dest) {
                                toclevel = buf.text().getTocLevel(distance(bgn, dest));
@@ -403,24 +437,31 @@ static void outline(OutlineOp mode, Cursor & cur)
                        }
                        // One such was found:
                        pit_type newpit = distance(bgn, dest);
-                       buf.undo().recordUndo(cur, ATOMIC_UNDO, pit, newpit - 1);
+                       buf.undo().recordUndo(cur, pit, newpit - 1);
                        pit_type const len = distance(start, finish);
                        pars.splice(dest, start, finish);
                        cur.pit() = newpit - len;
                        break;
                }
-               case OutlineIn: {
+               case OutlineIn:
+               case OutlineOut: {
                        pit_type const len = distance(start, finish);
-                       buf.undo().recordUndo(cur, ATOMIC_UNDO, pit, pit + len - 1);
+                       buf.undo().recordUndo(cur, pit, pit + len - 1);
                        for (; start != finish; ++start) {
                                toclevel = buf.text().getTocLevel(distance(bgn, start));
                                if (toclevel == Layout::NOT_IN_TOC)
                                        continue;
+
+                               DocumentClass const & tc = buf.params().documentClass();
                                DocumentClass::const_iterator lit = tc.begin();
                                DocumentClass::const_iterator len = tc.end();
+                               int const newtoclevel = 
+                                       (mode == OutlineIn ? toclevel + 1 : toclevel - 1);
+                               LabelType const oldlabeltype = start->layout().labeltype;
+
                                for (; lit != len; ++lit) {
-                                       if (lit->toclevel == toclevel + 1 &&
-                                           start->layout().labeltype == lit->labeltype) {
+                                       if (lit->toclevel ==  newtoclevel &&
+                                            lit->labeltype == oldlabeltype) {
                                                start->setLayout(*lit);
                                                break;
                                        }
@@ -428,25 +469,6 @@ static void outline(OutlineOp mode, Cursor & cur)
                        }
                        break;
                }
-               case OutlineOut: {
-                       pit_type const len = distance(start, finish);
-                       buf.undo().recordUndo(cur, ATOMIC_UNDO, pit, pit + len - 1);
-                       for (; start != finish; ++start) {
-                               toclevel = buf.text().getTocLevel(distance(bgn, start));
-                               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;
-               }
        }
 }
 
@@ -490,6 +512,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        cur.noScreenUpdate();
 
        LBUFERR(this == cur.text());
+       
+       // NOTE: This should NOT be a reference. See commit 94a5481a.
        CursorSlice const oldTopSlice = cur.top();
        bool const oldBoundary = cur.boundary();
        bool const oldSelection = cur.selection();
@@ -508,7 +532,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_PARAGRAPH_MOVE_DOWN: {
                pit_type const pit = cur.pit();
-               recUndo(cur, pit, pit + 1);
+               cur.recordUndo(pit, pit + 1);
                cur.finishUndo();
                pars_.swap(pit, pit + 1);
                needsUpdate = true;
@@ -519,7 +543,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_PARAGRAPH_MOVE_UP: {
                pit_type const pit = cur.pit();
-               recUndo(cur, pit - 1, pit);
+               cur.recordUndo(pit - 1, pit);
                cur.finishUndo();
                pars_.swap(pit, pit - 1);
                --cur.pit();
@@ -538,7 +562,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                // FIXME: this don't work for multipart document!
                for (pit_type tmp = 0, end = pars_.size(); tmp != end; ++tmp) {
                        if (pars_[tmp].params().startOfAppendix()) {
-                               recUndo(cur, tmp);
+                               cur.recordUndo(tmp, tmp);
                                pars_[tmp].params().startOfAppendix(false);
                                break;
                        }
@@ -616,26 +640,15 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                cur.screenUpdateFlags(Update::FitCursor);
                break;
 
-       case LFUN_INSET_SELECT_ALL:
-               if (cur.depth() == 1 || !cur.selection() || !cur.selBegin().at_begin()
-                         || !cur.selEnd().at_end()) {
-                       needsUpdate |= cur.selHandle(false);
-                       needsUpdate |= cursorTop(cur);
-                       needsUpdate |= cur.selHandle(true);
-                       needsUpdate |= cursorBottom(cur);
-               } else
-                       cur.undispatched();
-               cur.screenUpdateFlags(Update::FitCursor);
-               break;
-
        case LFUN_CHAR_FORWARD:
-       case LFUN_CHAR_FORWARD_SELECT:
+       case LFUN_CHAR_FORWARD_SELECT: {
                //LYXERR0(" LFUN_CHAR_FORWARD[SEL]:\n" << cur);
                needsUpdate |= cur.selHandle(act == LFUN_CHAR_FORWARD_SELECT);
-               needsUpdate |= cursorForward(cur);
+               bool const cur_moved = cursorForward(cur);
+               needsUpdate |= cur_moved;
 
-               if (!needsUpdate && oldTopSlice == cur.top()
-                               && cur.boundary() == oldBoundary) {
+               if (!cur_moved && oldTopSlice == cur.top()
+                              && cur.boundary() == oldBoundary) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_FORWARD);
 
@@ -654,15 +667,17 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        }
                }
                break;
+       }
 
        case LFUN_CHAR_BACKWARD:
-       case LFUN_CHAR_BACKWARD_SELECT:
+       case LFUN_CHAR_BACKWARD_SELECT: {
                //lyxerr << "handle LFUN_CHAR_BACKWARD[_SELECT]:\n" << cur << endl;
                needsUpdate |= cur.selHandle(act == LFUN_CHAR_BACKWARD_SELECT);
-               needsUpdate |= cursorBackward(cur);
+               bool const cur_moved = cursorBackward(cur);
+               needsUpdate |= cur_moved;
 
-               if (!needsUpdate && oldTopSlice == cur.top()
-                       && cur.boundary() == oldBoundary) {
+               if (!cur_moved && oldTopSlice == cur.top()
+                              && cur.boundary() == oldBoundary) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
 
@@ -681,14 +696,16 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        }
                }
                break;
+       }
 
        case LFUN_CHAR_LEFT:
        case LFUN_CHAR_LEFT_SELECT:
                if (lyxrc.visual_cursor) {
                        needsUpdate |= cur.selHandle(act == LFUN_CHAR_LEFT_SELECT);
-                       needsUpdate |= cursorVisLeft(cur);
-                       if (!needsUpdate && oldTopSlice == cur.top()
-                                       && cur.boundary() == oldBoundary) {
+                       bool const cur_moved = cursorVisLeft(cur);
+                       needsUpdate |= cur_moved;
+                       if (!cur_moved && oldTopSlice == cur.top()
+                                      && cur.boundary() == oldBoundary) {
                                cur.undispatched();
                                cmd = FuncRequest(LFUN_FINISHED_LEFT);
                        }
@@ -709,9 +726,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_CHAR_RIGHT_SELECT:
                if (lyxrc.visual_cursor) {
                        needsUpdate |= cur.selHandle(cmd.action() == LFUN_CHAR_RIGHT_SELECT);
-                       needsUpdate |= cursorVisRight(cur);
-                       if (!needsUpdate && oldTopSlice == cur.top()
-                                       && cur.boundary() == oldBoundary) {
+                       bool const cur_moved = cursorVisRight(cur);
+                       needsUpdate |= cur_moved;
+                       if (!cur_moved && oldTopSlice == cur.top()
+                                      && cur.boundary() == oldBoundary) {
                                cur.undispatched();
                                cmd = FuncRequest(LFUN_FINISHED_RIGHT);
                        }
@@ -787,7 +805,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                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);
+               ParagraphList::iterator start = next(bgn, pit);
                // The final paragraph of area to be selected:
                ParagraphList::iterator finish = start;
                ParagraphList::iterator end = pars.end();
@@ -820,9 +838,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_WORD_RIGHT_SELECT:
                if (lyxrc.visual_cursor) {
                        needsUpdate |= cur.selHandle(cmd.action() == LFUN_WORD_RIGHT_SELECT);
-                       needsUpdate |= cursorVisRightOneWord(cur);
-                       if (!needsUpdate && oldTopSlice == cur.top()
-                                       && cur.boundary() == oldBoundary) {
+                       bool const cur_moved = cursorVisRightOneWord(cur);
+                       needsUpdate |= cur_moved;
+                       if (!cur_moved && oldTopSlice == cur.top()
+                                      && cur.boundary() == oldBoundary) {
                                cur.undispatched();
                                cmd = FuncRequest(LFUN_FINISHED_RIGHT);
                        }
@@ -840,12 +859,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_WORD_FORWARD:
-       case LFUN_WORD_FORWARD_SELECT:
+       case LFUN_WORD_FORWARD_SELECT: {
                needsUpdate |= cur.selHandle(cmd.action() == LFUN_WORD_FORWARD_SELECT);
-               needsUpdate |= cursorForwardOneWord(cur);
+               bool const cur_moved = cursorForwardOneWord(cur);
+               needsUpdate |= cur_moved;
 
-               if (!needsUpdate && oldTopSlice == cur.top()
-                               && cur.boundary() == oldBoundary) {
+               if (!cur_moved && oldTopSlice == cur.top()
+                              && cur.boundary() == oldBoundary) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_FORWARD);
 
@@ -864,14 +884,16 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        }
                }
                break;
+       }
 
        case LFUN_WORD_LEFT:
        case LFUN_WORD_LEFT_SELECT:
                if (lyxrc.visual_cursor) {
                        needsUpdate |= cur.selHandle(cmd.action() == LFUN_WORD_LEFT_SELECT);
-                       needsUpdate |= cursorVisLeftOneWord(cur);
-                       if (!needsUpdate && oldTopSlice == cur.top()
-                                       && cur.boundary() == oldBoundary) {
+                       bool const cur_moved = cursorVisLeftOneWord(cur);
+                       needsUpdate |= cur_moved;
+                       if (!cur_moved && oldTopSlice == cur.top()
+                                      && cur.boundary() == oldBoundary) {
                                cur.undispatched();
                                cmd = FuncRequest(LFUN_FINISHED_LEFT);
                        }
@@ -889,12 +911,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_WORD_BACKWARD:
-       case LFUN_WORD_BACKWARD_SELECT:
+       case LFUN_WORD_BACKWARD_SELECT: {
                needsUpdate |= cur.selHandle(cmd.action() == LFUN_WORD_BACKWARD_SELECT);
-               needsUpdate |= cursorBackwardOneWord(cur);
+               bool const cur_moved = cursorBackwardOneWord(cur);
+               needsUpdate |= cur_moved;
 
-               if (!needsUpdate && oldTopSlice == cur.top()
-                               && cur.boundary() == oldBoundary) {
+               if (!cur_moved && oldTopSlice == cur.top()
+                              && cur.boundary() == oldBoundary) {
                        cur.undispatched();
                        cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
 
@@ -914,6 +937,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        }
                }
                break;
+       }
 
        case LFUN_WORD_SELECT: {
                selectWord(cur, WHOLE_WORD);
@@ -1058,8 +1082,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                        needsUpdate |= backspace(cur);
                                        cur.resetAnchor();
                                }
-                               // It is possible to make it a lot faster still
-                               // just comment out the line below...
                        }
                } else {
                        cutSelection(cur, true, false);
@@ -1071,24 +1093,32 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                cap::replaceSelection(cur);
                pit_type pit = cur.pit();
                Paragraph const & par = pars_[pit];
-               Paragraph const & prevpar = pit > 0 ? pars_[pit - 1] : par;
-               if (pit > 0 && cur.pos() == par.beginOfBody()
-                   && ((prevpar.getDepth() > par.getDepth()
-                        && !par.layout().isEnvironment())
-                       || (prevpar.layout() != par.layout()
-                           && !par.layout().isCommand()
-                           && prevpar.layout().isEnvironment()))) {
-                       if (par.layout().isEnvironment()) {
+               pit_type prev = pit;
+               if (pit > 0) {
+                       if (!pars_[pit - 1].layout().isEnvironment())
+                               prev = depthHook(pit, par.getDepth());
+                       else if (pars_[pit - 1].getDepth() >= par.getDepth())
+                               prev = pit - 1;
+               }
+               if (prev < pit && cur.pos() == par.beginOfBody()
+                   && !par.isEnvSeparator(cur.pos())
+                   && !par.layout().isCommand()
+                   && pars_[prev].layout() != par.layout()
+                   && pars_[prev].layout().isEnvironment()) {
+                       if (par.layout().isEnvironment()
+                           && pars_[prev].getDepth() == par.getDepth()) {
                                docstring const layout = par.layout().name();
                                DocumentClass const & tc = bv->buffer().params().documentClass();
                                lyx::dispatch(FuncRequest(LFUN_LAYOUT, tc.plainLayout().name()));
                                lyx::dispatch(FuncRequest(LFUN_SEPARATOR_INSERT, "parbreak"));
-                               breakParagraph(cur, true);
+                               lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_BREAK, "inverse"));
                                lyx::dispatch(FuncRequest(LFUN_LAYOUT, layout));
                        } else {
                                lyx::dispatch(FuncRequest(LFUN_SEPARATOR_INSERT, "parbreak"));
                                breakParagraph(cur);
                        }
+                       Font const f(inherit_font, cur.current_font.language());
+                       pars_[cur.pit() - 1].resetFonts(f);
                } else {
                        breakParagraph(cur, cmd.argument() == "inverse");
                }
@@ -1119,13 +1149,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        /*
                        Paragraph & par = pars_[cur.pit()];
                        if (inset->lyxCode() == LABEL_CODE
-                               && !par.layout().counter.empty() {
+                               && !par.layout().counter.empty()) {
                                // Go to the end of the paragraph
                                // Warning: Because of Change-Tracking, the last
                                // position is 'size()' and not 'size()-1':
                                cur.pos() = par.size();
                                // Insert a new paragraph
-                               FuncRequest fr(LFUN_BREAK_PARAGRAPH);
+                               FuncRequest fr(LFUN_PARAGRAPH_BREAK);
                                dispatch(cur, fr);
                        }
                        */
@@ -1204,6 +1234,14 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        specialChar(cur, InsetSpecialChar::END_OF_SENTENCE);
                else if (name == "menu-separator")
                        specialChar(cur, InsetSpecialChar::MENU_SEPARATOR);
+               else if (name == "lyx")
+                       specialChar(cur, InsetSpecialChar::PHRASE_LYX);
+               else if (name == "tex")
+                       specialChar(cur, InsetSpecialChar::PHRASE_TEX);
+               else if (name == "latex")
+                       specialChar(cur, InsetSpecialChar::PHRASE_LATEX);
+               else if (name == "latex2e")
+                       specialChar(cur, InsetSpecialChar::PHRASE_LATEX2E);
                else if (name.empty())
                        lyxerr << "LyX function 'specialchar-insert' needs an argument." << endl;
                else
@@ -1297,8 +1335,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        else if (arg == "wmf")
                                type = Clipboard::WmfGraphicsType;
                        else
-                               // We used to assert, but couldn't the argument come from, say, the
-                               // minibuffer and just be mistyped?
+                               // we also check in getStatus()
                                LYXERR0("Unrecognized graphics type: " << arg);
 
                        pasteClipboardGraphics(cur, bv->buffer().errorList("Paste"), type);
@@ -1307,6 +1344,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                bv->buffer().errors("Paste");
                cur.clearSelection(); // bug 393
                cur.finishUndo();
+               bv->buffer().updatePreviews();
                break;
        }
 
@@ -1547,7 +1585,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_MOUSE_DOUBLE:
                if (cmd.button() == mouse_button::button1) {
-                       selectWord(cur, WHOLE_WORD_STRICT);
+                       selectWord(cur, WHOLE_WORD);
                        bv->cursor() = cur;
                }
                break;
@@ -1567,11 +1605,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        break;
 
                case mouse_button::button2:
-                       // Middle mouse pasting.
-                       bv->mouseSetCursor(cur);
-                       lyx::dispatch(
-                               FuncRequest(LFUN_COMMAND_ALTERNATIVES,
-                                           "selection-paste ; primary-selection-paste paragraph"));
+                       if (lyxrc.mouse_middlebutton_paste) {
+                               // Middle mouse pasting.
+                               bv->mouseSetCursor(cur);
+                               lyx::dispatch(
+                                       FuncRequest(LFUN_COMMAND_ALTERNATIVES,
+                                                   "selection-paste ; primary-selection-paste paragraph"));
+                       }
                        cur.noScreenUpdate();
                        break;
 
@@ -2280,6 +2320,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                arg += " lang=" + from_ascii(cur.getFont().language()->lang());
                        }
                }
+               if (lyxrc.thesaurusdir_path.empty()) {
+                       frontend::Alert::warning(_("Path to thesaurus directory not set!"),
+                                       _("The path to the thesaurus directory has not been specified.\n"
+                                         "The thesaurus is not functional.\n"
+                                         "Please refer to sec. 6.15.1 of the User's Guide for setup\n"
+                                         "instructions."));
+               }
                bv->showDialog("thesaurus", to_utf8(arg));
                break;
        }
@@ -2296,8 +2343,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                word = cur.selectionAsString(false);
                        }
                        lang = const_cast<Language *>(cur.getFont().language());
-               } else
+               } else if (cmd.getArg(1).empty()) {
+                       // optional language argument is missing
+                       // use the language at cursor position
+                       lang = const_cast<Language *>(cur.getFont().language());
+               } else {
                        lang = const_cast<Language *>(languages.getLanguage(cmd.getArg(1)));
+               }
                WordLangTuple wl(word, lang);
                theSpellChecker()->insert(wl);
                break;
@@ -2315,8 +2367,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                word = cur.selectionAsString(false);
                        }
                        lang = const_cast<Language *>(cur.getFont().language());
-               } else
+               } else if (cmd.getArg(1).empty()) {
+                       lang = const_cast<Language *>(cur.getFont().language());
+               } else {
                        lang = const_cast<Language *>(languages.getLanguage(cmd.getArg(1)));
+               }
                WordLangTuple wl(word, lang);
                theSpellChecker()->accept(wl);
                break;
@@ -2334,8 +2389,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                word = cur.selectionAsString(false);
                        }
                        lang = const_cast<Language *>(cur.getFont().language());
-               } else
+               } else if (cmd.getArg(1).empty()) {
+                       lang = const_cast<Language *>(cur.getFont().language());
+               } else {
                        lang = const_cast<Language *>(languages.getLanguage(cmd.getArg(1)));
+               }
                WordLangTuple wl(word, lang);
                theSpellChecker()->remove(wl);
                break;
@@ -2400,6 +2458,33 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                needsUpdate = true;
                break;
 
+       case LFUN_SERVER_GET_STATISTICS:
+               {
+                       DocIterator from, to;
+                       if (cur.selection()) {
+                               from = cur.selectionBegin();
+                               to = cur.selectionEnd();
+                       } else {
+                               from = doc_iterator_begin(cur.buffer());
+                               to = doc_iterator_end(cur.buffer());
+                       }
+
+                       cur.buffer()->updateStatistics(from, to);
+                       string const arg0 = cmd.getArg(0);
+                       if (arg0 == "words") {
+                               cur.message(convert<docstring>(cur.buffer()->wordCount()));
+                       } else if (arg0 == "chars") {
+                               cur.message(convert<docstring>(cur.buffer()->charCount(false)));
+                       } else if (arg0 == "chars-space") {
+                               cur.message(convert<docstring>(cur.buffer()->charCount(true)));
+                       } else {
+                               cur.message(convert<docstring>(cur.buffer()->wordCount()) + " "
+                               + convert<docstring>(cur.buffer()->charCount(false)) + " "
+                               + convert<docstring>(cur.buffer()->charCount(true)));
+                       }
+               }
+               break;
+
        default:
                LYXERR(Debug::ACTION, "Command " << cmd << " not DISPATCHED by Text");
                cur.undispatched();
@@ -2623,11 +2708,8 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_CAPTION_INSERT: {
                code = CAPTION_CODE;
                string arg = cmd.getArg(0);
-               bool varia = arg != "LongTableNoNumber";
-               if (cur.depth() > 0) {
-                       if (&cur[cur.depth() - 1].inset())
-                               varia = cur[cur.depth() - 1].inset().allowsCaptionVariation(arg);
-               }
+               bool varia = arg != "LongTableNoNumber"
+                       && cur.inset().allowsCaptionVariation(arg);
                // not allowed in description items,
                // and in specific insets
                enable = !inDescriptionItem(cur)
@@ -2881,22 +2963,30 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                        break;
                }
 
-               // explicit graphics type?
                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);
+               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 if (arg == "emf")
+                       type = Clipboard::EmfGraphicsType;
+               else if (arg == "wmf")
+                       type = Clipboard::WmfGraphicsType;
+               else {
+                       // unknown argument
+                       LYXERR0("Unrecognized graphics type: " << arg);
+                       // we don't want to assert if the user just mistyped the LFUN
+                       LATTEST(cmd.origin() != FuncRequest::INTERNAL);
+                       enable = false;
                        break;
                }
-
-               // unknown argument
-               enable = false;
+               enable = theClipboard().hasGraphicsContents(type);
                break;
-        }
+       }
 
        case LFUN_CLIPBOARD_PASTE:
        case LFUN_CLIPBOARD_PASTE_SIMPLE:
@@ -2987,18 +3077,31 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                break;
 
        case LFUN_PARAGRAPH_BREAK:
-               enable = cur.inset().getLayout().isMultiPar();
+               enable = inset().allowMultiPar();
                break;
 
        case LFUN_SPELLING_ADD:
        case LFUN_SPELLING_IGNORE:
        case LFUN_SPELLING_REMOVE:
-               enable = theSpellChecker();
+               enable = theSpellChecker() != NULL;
+               if (enable && !cmd.getArg(1).empty()) {
+                       // validate explicitly given language
+                       Language const * const lang = const_cast<Language *>(languages.getLanguage(cmd.getArg(1)));
+                       enable &= lang != NULL;
+               }
                break;
 
-       case LFUN_LAYOUT:
+       case LFUN_LAYOUT: {
                enable = !cur.inset().forcePlainLayout();
+
+               docstring layout = cmd.argument();
+               if (layout.empty()) {
+                       DocumentClass const & tclass = cur.buffer()->params().documentClass();
+                       layout = tclass.defaultLayoutName();
+               }
+               flag.setOnOff(layout == cur.paragraph().layout().name());
                break;
+       }
 
        case LFUN_ENVIRONMENT_SPLIT: {
                if (cmd.argument() == "outer") {
@@ -3100,7 +3203,6 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_INSET_END:
        case LFUN_INSET_BEGIN_SELECT:
        case LFUN_INSET_END_SELECT:
-       case LFUN_INSET_SELECT_ALL:
        case LFUN_PARAGRAPH_UP:
        case LFUN_PARAGRAPH_DOWN:
        case LFUN_LINE_BEGIN:
@@ -3118,6 +3220,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_UNICODE_INSERT:
        case LFUN_THESAURUS_ENTRY:
        case LFUN_ESCAPE:
+       case LFUN_SERVER_GET_STATISTICS:
                // these are handled in our dispatch()
                enable = true;
                break;