]> git.lyx.org Git - lyx.git/blobdiff - src/Text3.cpp
* doInsertInset(): cosmetics
[lyx.git] / src / Text3.cpp
index 7b6a8f624ed4465e36177a3b889d204fa7eb86e3..d5c1051080f85566edc0938071a51a744abfd385 100644 (file)
 #include "BufferView.h"
 #include "Cursor.h"
 #include "CutAndPaste.h"
-#include "debug.h"
 #include "DispatchResult.h"
 #include "ErrorList.h"
 #include "factory.h"
 #include "FuncRequest.h"
-#include "gettext.h"
 #include "InsetList.h"
 #include "Intl.h"
 #include "Language.h"
@@ -44,7 +42,6 @@
 #include "Paragraph.h"
 #include "paragraph_funcs.h"
 #include "ParagraphParameters.h"
-#include "ParIterator.h"
 #include "TextClass.h"
 #include "TextMetrics.h"
 #include "VSpace.h"
 #include "insets/InsetText.h"
 #include "insets/InsetInfo.h"
 
-#include "support/lstrings.h"
-#include "support/lyxlib.h"
 #include "support/convert.h"
+#include "support/debug.h"
+#include "support/gettext.h"
+#include "support/lstrings.h"
 #include "support/lyxtime.h"
 
 #include "mathed/InsetMathHull.h"
 #include "mathed/MathMacroTemplate.h"
 
-#include <boost/current_function.hpp>
 #include <boost/next_prior.hpp>
 
 #include <clocale>
 #include <sstream>
 
-using std::endl;
-using std::string;
-using std::istringstream;
-using std::ostringstream;
+using namespace std;
+using namespace lyx::support;
 
 namespace lyx {
 
 using cap::copySelection;
 using cap::cutSelection;
 using cap::pasteFromStack;
-using cap::pasteClipboard;
+using cap::pasteClipboardText;
+using cap::pasteClipboardGraphics;
 using cap::replaceSelection;
 
-using support::isStrUnsignedInt;
-using support::token;
-
 // globals...
 static Font freefont(ignore_font, ignore_language);
 static bool toggleall = false;
@@ -156,6 +149,7 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display)
                // somewhere, and an ordinary formula
                // otherwise
                if (sel.find(from_ascii("\\newcommand")) == string::npos
+                               && sel.find(from_ascii("\\newlyxcommand")) == string::npos
                                && sel.find(from_ascii("\\def")) == string::npos)
                {
                        InsetMathHull * formula = new InsetMathHull;
@@ -188,57 +182,61 @@ static void specialChar(Cursor & cur, InsetSpecialChar::Kind kind)
 static bool doInsertInset(Cursor & cur, Text * text,
        FuncRequest const & cmd, bool edit, bool pastesel)
 {
-       Inset * inset = createInset(cur.bv().buffer(), cmd);
+       Buffer & buffer = cur.bv().buffer();
+       BufferParams const & bparams = buffer.params();
+       Inset * inset = createInset(buffer, cmd);
        if (!inset)
                return false;
 
        if (InsetCollapsable * ci = inset->asInsetCollapsable())
-               ci->setLayout(cur.bv().buffer().params());
+               ci->setLayout(bparams);
 
        cur.recordUndo();
        if (cmd.action == LFUN_INDEX_INSERT) {
-               docstring ds = support::subst(text->getStringToIndex(cur), '\n', ' ');
+               docstring ds = subst(text->getStringToIndex(cur), '\n', ' ');
                text->insertInset(cur, inset);
                if (edit)
                        inset->edit(cur, true);
                // Now put this into inset
                static_cast<InsetCollapsable *>(inset)->text_.insertStringAsParagraphs(cur, ds);
-       } else {
-               bool gotsel = false;
-               if (cur.selection()) {
-                       lyx::dispatch(FuncRequest(LFUN_CUT));
-                       gotsel = true;
-               }
-               text->insertInset(cur, inset);
+               return true;
+       }
 
-               if (edit)
-                       inset->edit(cur, true);
+       bool gotsel = false;
+       if (cur.selection()) {
+               lyx::dispatch(FuncRequest(LFUN_CUT));
+               gotsel = true;
+       }
+       text->insertInset(cur, inset);
 
-               if (gotsel && pastesel) {
-                       lyx::dispatch(FuncRequest(LFUN_PASTE, "0"));
-                       InsetText * insetText = dynamic_cast<InsetText *>(inset);
-                       if (insetText && !insetText->allowMultiPar() 
-                           || cur.lastpit() == 0) {
-                               // reset first par to default
-                               LayoutPtr const layout =
-                                       cur.buffer().params().getTextClass().defaultLayout();
-                               cur.text()->paragraphs().begin()->layout(layout);
-                               cur.pos() = 0;
-                               cur.pit() = 0;
-                               // Merge multiple paragraphs -- hack
-                               while (cur.lastpit() > 0) {
-                                       mergeParagraph(cur.buffer().params(),
-                                               cur.text()->paragraphs(), 0);
-                               }
-                       } else {
-                               // reset surrounding par to default
-                               docstring const layoutname = 
-                                       cur.buffer().params().getTextClass().defaultLayoutName();
-                               cur.leaveInset(*inset);
-                               text->setLayout(cur, layoutname);
-                       }
-               }
+       if (edit)
+               inset->edit(cur, true);
+
+       if (!gotsel || !pastesel)
+               return true;
+
+       lyx::dispatch(FuncRequest(LFUN_PASTE, "0"));
+       InsetText * insetText = dynamic_cast<InsetText *>(inset);
+       if (insetText && !insetText->allowMultiPar() || cur.lastpit() == 0) {
+               // reset first par to default
+               LayoutPtr const layout = insetText->useEmptyLayout()
+                       ? bparams.getTextClass().emptyLayout()
+                       : bparams.getTextClass().defaultLayout();
+               cur.text()->paragraphs().begin()->layout(layout);
+               cur.pos() = 0;
+               cur.pit() = 0;
+               // Merge multiple paragraphs -- hack
+               while (cur.lastpit() > 0)
+                       mergeParagraph(bparams, cur.text()->paragraphs(), 0);
+       } else {
+               // reset surrounding par to default
+               docstring const layoutname = insetText->useEmptyLayout()
+                       ? bparams.getTextClass().emptyLayoutName()
+                       : bparams.getTextClass().defaultLayoutName();
+               cur.leaveInset(*inset);
+               text->setLayout(cur, layoutname);
        }
+
        return true;
 }
 
@@ -304,8 +302,8 @@ static void outline(OutlineOp mode, Cursor & cur)
                        // Not found; do nothing
                        if (toclevel == Layout::NOT_IN_TOC || toclevel > thistoclevel)
                                break;
-                       pit_type const newpit = std::distance(bgn, dest);
-                       pit_type const len = std::distance(start, finish);
+                       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);
                        pars.insert(dest, start, finish);
@@ -337,8 +335,8 @@ static void outline(OutlineOp mode, Cursor & cur)
                                        break;
                        }
                        // One such was found:
-                       pit_type newpit = std::distance(bgn, dest);
-                       pit_type const len = std::distance(start, finish);
+                       pit_type newpit = distance(bgn, dest);
+                       pit_type const len = distance(start, finish);
                        buf.undo().recordUndo(cur, ATOMIC_UNDO, pit, newpit - 1);
                        pars.insert(dest, start, finish);
                        start = boost::next(bgn, pit);
@@ -419,7 +417,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                pit_type const pit = cur.pit();
                recUndo(cur, pit, pit + 1);
                cur.finishUndo();
-               std::swap(pars_[pit], pars_[pit + 1]);
+               swap(pars_[pit], pars_[pit + 1]);
                updateLabels(cur.buffer());
                needsUpdate = true;
                ++cur.pit();
@@ -430,7 +428,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                pit_type const pit = cur.pit();
                recUndo(cur, pit - 1, pit);
                cur.finishUndo();
-               std::swap(pars_[pit], pars_[pit - 1]);
+               swap(pars_[pit], pars_[pit - 1]);
                updateLabels(cur.buffer());
                --cur.pit();
                needsUpdate = true;
@@ -493,6 +491,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                } else {
                        cur.undispatched();
                }
+               cur.updateFlags(Update::FitCursor);
                break;
 
        case LFUN_BUFFER_END:
@@ -503,12 +502,12 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                } else {
                        cur.undispatched();
                }
+               cur.updateFlags(Update::FitCursor);
                break;
 
        case LFUN_CHAR_FORWARD:
        case LFUN_CHAR_FORWARD_SELECT:
-               //lyxerr << BOOST_CURRENT_FUNCTION
-               //       << " LFUN_CHAR_FORWARD[SEL]:\n" << cur << endl;
+               //LYXERR0(" LFUN_CHAR_FORWARD[SEL]:\n" << cur);
                needsUpdate |= cur.selHandle(cmd.action == LFUN_CHAR_FORWARD_SELECT);
                needsUpdate |= cursorForward(cur);
 
@@ -534,29 +533,50 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_CHAR_LEFT:
        case LFUN_CHAR_LEFT_SELECT:
-               //FIXME: for visual cursor, really move left
-               if (reverseDirectionNeeded(cur)) {
-                       cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ? 
-                                       LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
+               if (lyxrc.visual_cursor) {
+                       needsUpdate |= cur.selHandle(cmd.action == LFUN_CHAR_LEFT_SELECT);
+                       needsUpdate |= cursorVisLeft(cur);
+                       if (!needsUpdate && oldTopSlice == cur.top()
+                                       && cur.boundary() == oldBoundary) {
+                               cur.undispatched();
+                               cmd = FuncRequest(LFUN_FINISHED_LEFT);
+                       }
                } else {
-                       cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ? 
+                       if (reverseDirectionNeeded(cur)) {
+                               cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ? 
+                                       LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
+                       } else {
+                               cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ? 
                                        LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
+                       }
+                       dispatch(cur, cmd);
+                       return;
                }
-               dispatch(cur, cmd);
-               return;
+               break;
 
        case LFUN_CHAR_RIGHT:
        case LFUN_CHAR_RIGHT_SELECT:
-               //FIXME: for visual cursor, really move right
-               if (reverseDirectionNeeded(cur)) {
-                       cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ? 
-                                       LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
+               if (lyxrc.visual_cursor) {
+                       needsUpdate |= cur.selHandle(cmd.action == LFUN_CHAR_RIGHT_SELECT);
+                       needsUpdate |= cursorVisRight(cur);
+                       if (!needsUpdate && oldTopSlice == cur.top()
+                                       && cur.boundary() == oldBoundary) {
+                               cur.undispatched();
+                               cmd = FuncRequest(LFUN_FINISHED_RIGHT);
+                       }
                } else {
-                       cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ? 
+                       if (reverseDirectionNeeded(cur)) {
+                               cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ? 
+                                       LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
+                       } else {
+                               cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ? 
                                        LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
+                       }
+                       dispatch(cur, cmd);
+                       return;
                }
-               dispatch(cur, cmd);
-               return;
+               break;
+               
 
        case LFUN_UP_SELECT:
        case LFUN_DOWN_SELECT:
@@ -670,7 +690,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_BREAK_LINE: {
+       case LFUN_NEW_LINE: {
                // Not allowed by LaTeX (labels or empty par)
                if (cur.pos() > cur.paragraph().beginOfBody()) {
                        // this avoids a double undo
@@ -684,6 +704,21 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                }
                break;
        }
+       
+       case LFUN_LINE_BREAK: {
+               // Not allowed by LaTeX (labels or empty par)
+               if (cur.pos() > cur.paragraph().beginOfBody()) {
+                       // this avoids a double undo
+                       // FIXME: should not be needed, ideally
+                       if (!cur.selection())
+                               cur.recordUndo();
+                       cap::replaceSelection(cur);
+                       cur.insert(new InsetLinebreak);
+                       cur.posForward();
+                       moveCursor(cur, false);
+               }
+               break;
+       }
 
        case LFUN_CHAR_DELETE_FORWARD:
                if (!cur.selection()) {
@@ -858,25 +893,28 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                moveCursor(cur, false);
                break;
 
-       case LFUN_HYPHENATION_POINT_INSERT:
-               specialChar(cur, InsetSpecialChar::HYPHENATION);
-               break;
-
-       case LFUN_LIGATURE_BREAK_INSERT:
-               specialChar(cur, InsetSpecialChar::LIGATURE_BREAK);
-               break;
-
-       case LFUN_DOTS_INSERT:
-               specialChar(cur, InsetSpecialChar::LDOTS);
-               break;
-
-       case LFUN_END_OF_SENTENCE_PERIOD_INSERT:
-               specialChar(cur, InsetSpecialChar::END_OF_SENTENCE);
-               break;
-
-       case LFUN_MENU_SEPARATOR_INSERT:
-               specialChar(cur, InsetSpecialChar::MENU_SEPARATOR);
+       case LFUN_SPECIALCHAR_INSERT: {
+               string const name = to_utf8(cmd.argument());
+               if (name == "hyphenation")
+                       specialChar(cur, InsetSpecialChar::HYPHENATION);
+               else if (name == "ligature-break")
+                       specialChar(cur, InsetSpecialChar::LIGATURE_BREAK);
+               else if (name == "slash")
+                       specialChar(cur, InsetSpecialChar::SLASH);
+               else if (name == "nobreakdash")
+                       specialChar(cur, InsetSpecialChar::NOBREAKDASH);
+               else if (name == "dots")
+                       specialChar(cur, InsetSpecialChar::LDOTS);
+               else if (name == "end-of-sentence")
+                       specialChar(cur, InsetSpecialChar::END_OF_SENTENCE);
+               else if (name == "menu-separator")
+                       specialChar(cur, InsetSpecialChar::MENU_SEPARATOR);
+               else if (name.empty())
+                       lyxerr << "LyX function 'specialchar-insert' needs an argument." << endl;
+               else
+                       lyxerr << "Wrong argument for LyX function 'specialchar-insert'." << endl;
                break;
+       }
 
        case LFUN_WORD_UPCASE:
                changeCase(cur, text_uppercase);
@@ -894,22 +932,44 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                charsTranspose(cur);
                break;
 
-       case LFUN_PASTE:
+       case LFUN_PASTE: {
                cur.message(_("Paste"));
                cap::replaceSelection(cur);
-               if (cmd.argument().empty() && !theClipboard().isInternal())
-                       pasteClipboard(cur, bv->buffer().errorList("Paste"));
-               else {
-                       string const arg(to_utf8(cmd.argument()));
+
+               // without argument?
+               string const arg = to_utf8(cmd.argument());
+               if (arg.empty()) {
+                       if (theClipboard().isInternal())
+                               pasteFromStack(cur, bv->buffer().errorList("Paste"), 0);
+                       else if (theClipboard().hasGraphicsContents())
+                               pasteClipboardGraphics(cur, bv->buffer().errorList("Paste"));
+                       else
+                               pasteClipboardText(cur, bv->buffer().errorList("Paste"));
+               } else if (isStrUnsignedInt(arg)) {
+                       // we have a numerical argument
                        pasteFromStack(cur, bv->buffer().errorList("Paste"),
-                                       isStrUnsignedInt(arg) ?
-                                               convert<unsigned int>(arg) :
-                                               0);
+                                      convert<unsigned int>(arg));
+               } else {
+                       Clipboard::GraphicsType type;
+                       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
+                               BOOST_ASSERT(false);
+
+                       pasteClipboardGraphics(cur, bv->buffer().errorList("Paste"), type);
                }
+
                bv->buffer().errors("Paste");
                cur.clearSelection(); // bug 393
                cur.finishUndo();
                break;
+       }
 
        case LFUN_CUT:
                cutSelection(cur, true, true);
@@ -934,7 +994,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                is >> x >> y;
                if (!is)
                        lyxerr << "SETXY: Could not parse coordinates in '"
-                              << to_utf8(cmd.argument()) << std::endl;
+                              << to_utf8(cmd.argument()) << endl;
                else
                        tm.setCursorFromCoordinates(cur, x, y);
                break;
@@ -957,13 +1017,26 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                docstring layout = cmd.argument();
                LYXERR(Debug::INFO, "LFUN_LAYOUT: (arg) " << to_utf8(layout));
 
-               docstring const old_layout = cur.paragraph().layout()->name();
-
-               // Derive layout number from given argument (string)
-               // and current buffer's textclass (number)
+               Paragraph const & para = cur.paragraph();
+               docstring const old_layout = para.layout()->name();
                TextClass const & tclass = bv->buffer().params().getTextClass();
+
                if (layout.empty())
                        layout = tclass.defaultLayoutName();
+
+               if (para.forceEmptyLayout()) 
+                       // in this case only the empty layout is allowed
+                       layout = tclass.emptyLayoutName();
+               else if (para.useEmptyLayout()) {
+                       // in this case, default layout maps to empty layout 
+                       if (layout == tclass.defaultLayoutName())
+                               layout = tclass.emptyLayoutName();
+               } else { 
+                       // otherwise, the empty layout maps to the default
+                       if (layout == tclass.emptyLayoutName())
+                               layout = tclass.defaultLayoutName();
+               }
+
                bool hasLayout = tclass.hasLayout(layout);
 
                // If the entry is obsolete, use the new one instead.
@@ -1003,7 +1076,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_CLIPBOARD_PASTE:
                cur.clearSelection();
-               pasteClipboard(cur, bv->buffer().errorList("Paste"),
+               pasteClipboardText(cur, bv->buffer().errorList("Paste"),
                               cmd.argument() == "paragraph");
                bv->buffer().errors("Paste");
                break;
@@ -1017,8 +1090,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (cmd.argument().empty())
                        break;
                docstring hexstring = cmd.argument();
-               if (lyx::support::isHex(hexstring)) {
-                       char_type c = lyx::support::hexToInt(hexstring);
+               if (isHex(hexstring)) {
+                       char_type c = hexToInt(hexstring);
                        if (c >= 32 && c < 0x10ffff) {
                                lyxerr << "Inserting c: " << c << endl;
                                docstring s = docstring(1, c);
@@ -1144,7 +1217,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                CursorSlice old = bvcur.top();
 
                int const wh = bv->workHeight();
-               int const y = std::max(0, std::min(wh - 1, cmd.y));
+               int const y = max(0, min(wh - 1, cmd.y));
 
                tm.setCursorFromCoordinates(cur, cmd.x, y);
                cur.setTargetX(cmd.x);
@@ -1269,6 +1342,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        docstring ds = cur.selectionAsString(false);
                        cutSelection(cur, true, false);
                        static_cast<InsetInfo *>(inset)->setInfo(to_utf8(ds));
+                       static_cast<InsetInfo *>(inset)->updateInfo(cur.bv().buffer());
                }
                insertInset(cur, inset);
                cur.posForward();
@@ -1280,13 +1354,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 #endif
        case LFUN_CAPTION_INSERT:
        case LFUN_FOOTNOTE_INSERT:
-               // Open the inset, and move the current selection
-               // inside it.
-               doInsertInset(cur, this, cmd, true, true);
-               cur.posForward();
-               // These insets are numbered.
-               updateLabels(bv->buffer());
-               break;
        case LFUN_NOTE_INSERT:
        case LFUN_FLEX_INSERT:
        case LFUN_BOX_INSERT:
@@ -1297,10 +1364,14 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_MARGINALNOTE_INSERT:
        case LFUN_OPTIONAL_INSERT:
        case LFUN_ENVIRONMENT_INSERT:
+       case LFUN_INDEX_INSERT:
                // Open the inset, and move the current selection
                // inside it.
                doInsertInset(cur, this, cmd, true, true);
                cur.posForward();
+               // Some insets are numbered, others are shown in the outline pane so
+               // let's update the labels and the toc backend.
+               updateLabels(bv->buffer());
                break;
 
        case LFUN_TABULAR_INSERT:
@@ -1326,7 +1397,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                // add a separate paragraph for the caption inset
                pars.push_back(Paragraph());
                pars.back().setInsetOwner(pars[0].inInset());
-               pars.back().layout(tclass.defaultLayout());
+               if (pars.back().useEmptyLayout())
+                       pars.back().layout(tclass.emptyLayout());
+               else
+                       pars.back().layout(tclass.defaultLayout());
 
                int cap_pit = pars.size() - 1;
 
@@ -1336,8 +1410,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (!content) {
                        pars.push_back(Paragraph());
                        pars.back().setInsetOwner(pars[0].inInset());
-                       pars.back().layout(tclass.defaultLayout());
-
+                       if (pars.back().useEmptyLayout())
+                               pars.back().layout(tclass.emptyLayout());
+                       else
+                               pars.back().layout(tclass.defaultLayout());
                }
 
                // reposition the cursor to the caption
@@ -1355,11 +1431,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_INDEX_INSERT:
-               doInsertInset(cur, this, cmd, true, true);
-               cur.posForward();
-               break;
-
        case LFUN_NOMENCL_INSERT: {
                FuncRequest cmd1 = cmd;
                if (cmd.argument().empty())
@@ -1422,8 +1493,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        string const s1 = token(s, ' ', 1);
                        int const nargs = s1.empty() ? 0 : convert<int>(s1);
                        string const s2 = token(s, ' ', 2);
-                       string const type = s2.empty() ? "newcommand" : s2;
-                       cur.insert(new MathMacroTemplate(from_utf8(token(s, ' ', 0)), nargs, false, from_utf8(type)));
+                       MacroType type = MacroTypeNewcommand;
+                       if (s2 == "def")
+                               type = MacroTypeDef;
+                       cur.insert(new MathMacroTemplate(from_utf8(token(s, ' ', 0)), nargs, false, type));
                        //cur.nextInset()->edit(cur, true);
                }
                break;
@@ -1440,12 +1513,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_MATH_MATRIX:
        case LFUN_MATH_DELIM:
        case LFUN_MATH_BIGDELIM: {
-               if (cur.selection())
-                       cur.clearSelection();
-               // FIXME: instead of the above, this one
-               // should be used (but it asserts with Bidi enabled)
-               // cf. http://bugzilla.lyx.org/show_bug.cgi?id=4055
-               // cap::replaceSelection(cur);
+               cap::replaceSelection(cur);
                cur.insert(new InsetMathHull(hullSimple));
                checkAndActivateInset(cur, true);
                BOOST_ASSERT(cur.inMathed());
@@ -1547,18 +1615,24 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_FINISHED_LEFT:
                LYXERR(Debug::DEBUG, "handle LFUN_FINISHED_LEFT:\n" << cur);
-               if (reverseDirectionNeeded(cur)) {
-                       ++cur.pos();
-                       cur.setCurrentFont();
-               }
+               // We're leaving an inset, going left. If the inset is LTR, we're 
+               // leaving from the front, so we should not move (remain at --- but
+               // not in --- the inset). If the inset is RTL, move left, without 
+               // entering the inset itself; i.e., move to after the inset.
+               if (cur.paragraph().getFontSettings(
+                               cur.bv().buffer().params(), cur.pos()).isRightToLeft())
+                       cursorVisLeft(cur, true);
                break;
 
        case LFUN_FINISHED_RIGHT:
                LYXERR(Debug::DEBUG, "handle LFUN_FINISHED_RIGHT:\n" << cur);
-               if (!reverseDirectionNeeded(cur)) {
-                       ++cur.pos();
-                       cur.setCurrentFont();
-               }
+               // We're leaving an inset, going right. If the inset is RTL, we're 
+               // leaving from the front, so we should not move (remain at --- but
+               // not in --- the inset). If the inset is LTR, move right, without 
+               // entering the inset itself; i.e., move to after the inset.
+               if (!cur.paragraph().getFontSettings(
+                               cur.bv().buffer().params(), cur.pos()).isRightToLeft())
+                       cursorVisRight(cur, true);
                break;
 
        case LFUN_FINISHED_BACKWARD:
@@ -1584,7 +1658,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                params2string(cur.paragraph(), data);
 
                // Will the paragraph accept changes from the dialog?
-               bool const accept = !cur.inset().forceDefaultParagraphs(cur.idx());
+               bool const accept = 
+                       cur.inset().allowParagraphCustomization(cur.idx());
 
                data = "update " + convert<string>(accept) + '\n' + data;
                bv->updateDialog("paragraph", data);
@@ -1627,6 +1702,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                breakParagraph(cur);
                        }
 
+                       //FIXME Check if this should be emptyLayout()
                        setLayout(cur, tclass.defaultLayoutName());
                        ParagraphParameters p;
                        setParagraphs(cur, p);
@@ -1724,8 +1800,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        default:
-               LYXERR(Debug::ACTION, BOOST_CURRENT_FUNCTION
-                       << ": Command " << cmd << " not DISPATCHED by Text");
+               LYXERR(Debug::ACTION, "Command " << cmd << " not DISPATCHED by Text");
                cur.undispatched();
                break;
        }
@@ -1943,12 +2018,8 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                // always allow this, since we will inset a raw quote
                // if an inset is not allowed.
                break;
-       case LFUN_HYPHENATION_POINT_INSERT:
-       case LFUN_LIGATURE_BREAK_INSERT:
        case LFUN_HFILL_INSERT:
-       case LFUN_MENU_SEPARATOR_INSERT:
-       case LFUN_DOTS_INSERT:
-       case LFUN_END_OF_SENTENCE_PERIOD_INSERT:
+       case LFUN_SPECIALCHAR_INSERT:
                code = SPECIALCHAR_CODE;
                break;
        case LFUN_SPACE_INSERT:
@@ -1994,22 +2065,37 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                enable = cur.selection();
                break;
 
-       case LFUN_PASTE:
+       case LFUN_PASTE: {
                if (cmd.argument().empty()) {
                        if (theClipboard().isInternal())
                                enable = cap::numberOfSelections() > 0;
                        else
                                enable = !theClipboard().empty();
-               } else {
-                       string const arg = to_utf8(cmd.argument());
-                       if (isStrUnsignedInt(arg)) {
-                               unsigned int n = convert<unsigned int>(arg);
-                               enable = cap::numberOfSelections() > n;
-                       } else
-                               // unknown argument
-                               enable = false;
+                       break;
+               }
+               
+               // we have an argument
+               string const arg = to_utf8(cmd.argument());
+               if (isStrUnsignedInt(arg)) {
+                       // it's a number and therefore means the internal stack
+                       unsigned int n = convert<unsigned int>(arg);
+                       enable = cap::numberOfSelections() > n;
+                       break;
                }
+               
+               // explicit graphics type?
+               if ((arg == "pdf" && theClipboard().hasGraphicsContents(Clipboard::PdfGraphicsType))
+                   || (arg == "png" && theClipboard().hasGraphicsContents(Clipboard::PngGraphicsType))
+                   || (arg == "jpeg" && theClipboard().hasGraphicsContents(Clipboard::JpegGraphicsType))
+                   || (arg == "linkback" && theClipboard().hasGraphicsContents(Clipboard::LinkBackGraphicsType))) {
+                       enable = true;
+                       break;
+               }
+               
+               // unknown argument
+               enable = false;
                break;
+        }
 
        case LFUN_CLIPBOARD_PASTE:
                enable = !theClipboard().empty();
@@ -2089,8 +2175,9 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_PARAGRAPH_UP:
        case LFUN_PARAGRAPH_DOWN:
        case LFUN_LINE_BEGIN:
+       case LFUN_LINE_BREAK:
        case LFUN_LINE_END:
-       case LFUN_BREAK_LINE:
+       case LFUN_NEW_LINE:
        case LFUN_CHAR_DELETE_FORWARD:
        case LFUN_DELETE_FORWARD_SKIP:
        case LFUN_CHAR_DELETE_BACKWARD: