]> 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 cf76341c8216ea230716d6bc0276fb67845b1343..18ec4777ede673c72ab0bc88d36b403d575ccfb9 100644 (file)
@@ -56,6 +56,7 @@
 #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"
@@ -63,6 +64,7 @@
 #include "insets/InsetQuotes.h"
 #include "insets/InsetSpecialChar.h"
 #include "insets/InsetText.h"
+#include "insets/InsetWrap.h"
 
 #include "support/convert.h"
 #include "support/debug.h"
@@ -234,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) {
@@ -243,8 +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;
        }
 
@@ -297,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
@@ -326,6 +381,7 @@ 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;
@@ -461,6 +517,13 @@ 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())) {
@@ -866,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())
@@ -905,49 +1053,6 @@ 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();
 
@@ -1273,7 +1378,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                pos_type pos = cur.pos();
                BufferParams const & bufparams = bv->buffer().params();
                Layout const & style = par.layout();
-               InsetLayout const & ilayout = cur.inset().getLayout(bufparams);
+               InsetLayout const & ilayout = cur.inset().getLayout();
                if (!style.pass_thru && !ilayout.isPassThru()
                    && par.getFontSettings(bufparams, pos).language()->lang() != "hebrew") {
                        // this avoids a double undo
@@ -1697,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: {
@@ -2023,6 +2129,16 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                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");
@@ -2059,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
                //
@@ -2172,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;
@@ -2226,6 +2369,9 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_LABEL_INSERT:
                code = LABEL_CODE;
                break;
+       case LFUN_LINE_INSERT:
+               code = LINE_CODE;
+               break;
        case LFUN_INFO_INSERT:
                code = INFO_CODE;
                break;
@@ -2279,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
@@ -2378,7 +2537,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
 
        case LFUN_INSET_DISSOLVE:
                if (!cmd.argument().empty()) {
-                       InsetLayout const & 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
@@ -2411,6 +2570,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        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;
@@ -2421,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)
@@ -2432,17 +2597,10 @@ 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_MATH_INSERT:
-       case LFUN_MATH_MATRIX:
-       case LFUN_MATH_DELIM:
-       case LFUN_MATH_BIGDELIM:
-               // not allowed in ERT, for example.
-               enable = cur.inset().insetAllowed(MATH_CODE);
-               break;
-
        case LFUN_DATE_INSERT: {
                string const format = cmd.argument().empty()
                        ? lyxrc.date_insert_format : to_utf8(cmd.argument());
@@ -2450,6 +2608,12 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                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:
@@ -2485,8 +2649,6 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        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:
@@ -2497,19 +2659,12 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_SERVER_GET_LAYOUT:
        case LFUN_LAYOUT:
        case LFUN_SELF_INSERT:
-       case LFUN_LINE_INSERT:
-       case LFUN_MATH_DISPLAY:
-       case LFUN_MATH_MODE:
-       case LFUN_MATH_MACRO:
-       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:
@@ -2552,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;
 }