X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FText3.cpp;h=704adceac62febde4f794668ebcb5b3a94fd0360;hb=b8550d11e836e857967a31250e6ca248b2d43f82;hp=42ea91a2b002fe05fd522561d1034a1b16e2d2d5;hpb=f1cba8ff64b369792fd49f5ddf90e8126ab476ac;p=lyx.git diff --git a/src/Text3.cpp b/src/Text3.cpp index 42ea91a2b0..704adceac6 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -1,5 +1,5 @@ /** - * \file text3.cpp + * \file Text3.cpp * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * @@ -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" @@ -36,34 +37,40 @@ #include "Language.h" #include "Layout.h" #include "LyXAction.h" -#include "LyXFunc.h" +#include "LyX.h" #include "Lexer.h" #include "LyXRC.h" #include "Paragraph.h" -#include "paragraph_funcs.h" #include "ParagraphParameters.h" +#include "SpellChecker.h" #include "TextClass.h" #include "TextMetrics.h" #include "VSpace.h" +#include "WordLangTuple.h" +#include "frontends/Application.h" #include "frontends/Clipboard.h" #include "frontends/Selection.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 +91,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); @@ -134,7 +143,7 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display) #ifdef ENABLE_ASSERTIONS const int old_pos = cur.pos(); #endif - cur.insert(new InsetMathHull(hullSimple)); + cur.insert(new InsetMathHull(cur.buffer(), hullSimple)); #ifdef ENABLE_ASSERTIONS LASSERT(old_pos == cur.pos(), /**/); #endif @@ -158,7 +167,7 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display) && sel.find(from_ascii("\\newlyxcommand")) == string::npos && sel.find(from_ascii("\\def")) == string::npos) { - InsetMathHull * formula = new InsetMathHull; + InsetMathHull * formula = new InsetMathHull(cur.buffer()); string const selstr = to_utf8(sel); istringstream is(selstr); Lexer lex; @@ -177,7 +186,7 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display) } else cur.insert(formula); } else { - cur.insert(new MathMacroTemplate(sel)); + cur.insert(new MathMacroTemplate(cur.buffer(), sel)); } } if (valid) @@ -187,6 +196,27 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display) } +void regexpDispatch(Cursor & cur, FuncRequest const & cmd) +{ + LASSERT(cmd.action == LFUN_REGEXP_MODE, return); + if (cur.inRegexped()) { + cur.message(_("Already in regular expression mode")); + return; + } + cur.recordUndo(); + docstring sel = cur.selectionAsString(false); + + // It may happen that sel is empty but there is a selection + replaceSelection(cur); + + cur.insert(new InsetMathHull(cur.buffer(), hullRegexp)); + cur.nextInset()->edit(cur, true); + cur.niceInsert(sel); + + cur.message(_("Regexp editor mode")); +} + + static void specialChar(Cursor & cur, InsetSpecialChar::Kind kind) { cur.recordUndo(); @@ -201,12 +231,12 @@ static bool doInsertInset(Cursor & cur, Text * text, { Buffer & buffer = cur.bv().buffer(); BufferParams const & bparams = buffer.params(); - Inset * inset = createInset(buffer, cmd); + Inset * inset = createInset(&buffer, cmd); if (!inset) return false; if (InsetCollapsable * ci = inset->asInsetCollapsable()) - ci->setLayout(bparams); + ci->setButtonLabel(); cur.recordUndo(); if (cmd.action == LFUN_INDEX_INSERT) { @@ -215,8 +245,8 @@ static bool doInsertInset(Cursor & cur, Text * text, if (edit) inset->edit(cur, true); // Now put this into inset - static_cast(inset)-> - text().insertStringAsParagraphs(cur, ds); + cur.text()->insertStringAsLines(cur, ds, cur.current_font); + cur.leaveInset(*inset); return true; } @@ -234,21 +264,24 @@ 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(inset); - if (insetText && (!insetText->allowMultiPar() || cur.lastpit() == 0)) { - // reset first par to default - cur.text()->paragraphs().begin() - ->setPlainOrDefaultLayout(bparams.documentClass()); - cur.pos() = 0; - cur.pit() = 0; - // Merge multiple paragraphs -- hack - while (cur.lastpit() > 0) - mergeParagraph(bparams, cur.text()->paragraphs(), 0); - cur.leaveInset(*inset); + if (insetText) { + insetText->fixParagraphsFont(); + if (!insetText->allowMultiPar() || cur.lastpit() == 0) { + // reset first par to default + cur.text()->paragraphs().begin() + ->setPlainOrDefaultLayout(bparams.documentClass()); + cur.pos() = 0; + cur.pit() = 0; + // Merge multiple paragraphs -- hack + while (cur.lastpit() > 0) + mergeParagraph(bparams, cur.text()->paragraphs(), 0); + cur.leaveInset(*inset); + } } else { cur.leaveInset(*inset); // reset surrounding par to default @@ -258,7 +291,6 @@ static bool doInsertInset(Cursor & cur, Text * text, : dc.defaultLayoutName(); text->setLayout(cur, layoutname); } - return true; } @@ -280,15 +312,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(); @@ -298,12 +330,12 @@ 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; - } } switch (mode) { @@ -329,11 +361,9 @@ static void outline(OutlineOp mode, Cursor & cur) 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); - start = boost::next(pars.begin(), deletepit); - pit = newpit; - pars.erase(start, finish); - return; + pars.splice(dest, start, finish); + cur.pit() = newpit; + break; } case OutlineDown: { if (finish == end) @@ -345,19 +375,16 @@ 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); - 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); - pit = newpit - len; - pars.erase(start, finish); - return; + pit_type const len = distance(start, finish); + pars.splice(dest, start, finish); + cur.pit() = newpit - len; + break; } case OutlineIn: { pit_type const len = distance(start, finish); @@ -376,7 +403,7 @@ static void outline(OutlineOp mode, Cursor & cur) } } } - return; + break; } case OutlineOut: { pit_type const len = distance(start, finish); @@ -395,7 +422,7 @@ static void outline(OutlineOp mode, Cursor & cur) } } } - return; + break; } } } @@ -409,8 +436,9 @@ void Text::number(Cursor & cur) } -bool Text::isRTL(Buffer const & buffer, Paragraph const & par) const +bool Text::isRTL(Paragraph const & par) const { + Buffer const & buffer = owner_->buffer(); return par.isRTL(buffer.params()); } @@ -419,10 +447,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 @@ -447,8 +484,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) pit_type const pit = cur.pit(); recUndo(cur, pit, pit + 1); cur.finishUndo(); - swap(pars_[pit], pars_[pit + 1]); - updateLabels(cur.buffer()); + pars_.swap(pit, pit + 1); + cur.buffer()->updateBuffer(); needsUpdate = true; ++cur.pit(); break; @@ -458,8 +495,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) pit_type const pit = cur.pit(); recUndo(cur, pit - 1, pit); cur.finishUndo(); - swap(pars_[pit], pars_[pit - 1]); - updateLabels(cur.buffer()); + pars_.swap(pit, pit - 1); + cur.buffer()->updateBuffer(); --cur.pit(); needsUpdate = true; break; @@ -485,53 +522,83 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) par.params().startOfAppendix(start); // we can set the refreshing parameters now - updateLabels(cur.buffer()); + cur.buffer()->updateBuffer(); 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.top().at_begin()) + 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.top().at_end()) + needsUpdate |= cursorBottom(cur); + else + cur.undispatched(); + cur.updateFlags(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.updateFlags(Update::FitCursor); break; @@ -545,6 +612,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; @@ -558,6 +638,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; @@ -615,16 +708,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; } @@ -644,14 +745,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: @@ -735,6 +871,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()) @@ -774,56 +995,20 @@ 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(); - Inset * inset = createInset(bv->buffer(), cmd); + + // 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: - // http://bugzilla.lyx.org/show_bug.cgi?id=2154 + // http://www.lyx.org/trac/ticket/2154 // This automatically put the label inset _after_ a // numbered section. It should be possible to extend the mechanism // to any kind of LateX environement. @@ -847,29 +1032,21 @@ 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(*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; - } - // else, if there is an inset at the cursor, access this - Inset * next_inset = cur.nextInset(); - if (next_inset) { - next_inset->showInsetDialog(bv); - break; - } - // if not then access the underlying inset. - inset.showInsetDialog(bv); + case LFUN_INSET_DISSOLVE: { + if (dissolveInset(cur)) + needsUpdate = true; break; } @@ -954,7 +1131,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")); @@ -972,6 +1150,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, /**/); @@ -996,8 +1179,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_SERVER_GET_XY: cur.message(from_utf8( - convert(tm.cursorX(cur.top(), cur.boundary())) - + ' ' + convert(tm.cursorY(cur.top(), cur.boundary())))); + convert(tm->cursorX(cur.top(), cur.boundary())) + + ' ' + convert(tm->cursorY(cur.top(), cur.boundary())))); break; case LFUN_SERVER_SET_XY: { @@ -1009,7 +1192,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; } @@ -1028,7 +1211,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) if (layout.empty()) layout = tclass.defaultLayoutName(); - if (para.forcePlainLayout()) + if (owner_->forcePlainLayout()) // in this case only the empty layout is allowed layout = tclass.plainLayoutName(); else if (para.usePlainLayout()) { @@ -1090,6 +1273,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; @@ -1110,7 +1302,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 @@ -1126,7 +1319,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) else c = par.getChar(pos - 1); string arg = to_utf8(cmd.argument()); - cur.insert(new InsetQuotes(bv->buffer(), c, (arg == "single") + cur.insert(new InsetQuotes(cur.buffer(), c, (arg == "single") ? InsetQuotes::SingleQuotes : InsetQuotes::DoubleQuotes)); cur.posForward(); } @@ -1145,9 +1338,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; } @@ -1161,40 +1354,29 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; // Single-click on work area - case LFUN_MOUSE_PRESS: + case LFUN_MOUSE_PRESS: { // We are not marking a selection with the keyboard in any case. - cur.bv().cursor().setMark(false); + Cursor & bvcur = cur.bv().cursor(); + bvcur.setMark(false); switch (cmd.button()) { case mouse_button::button1: // Set the cursor if (!bv->mouseSetCursor(cur, cmd.argument() == "region-select")) cur.updateFlags(Update::SinglePar | Update::FitCursor); + if (bvcur.wordSelection()) + selectWord(bvcur, WHOLE_WORD); break; 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: { - Cursor const & bvcur = cur.bv().cursor(); // Don't do anything if we right-click a // selection, a context menu will popup. if (bvcur.selection() && cur >= bvcur.selectionBegin() @@ -1211,7 +1393,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) break; } // switch (cmd.button()) break; - + } case LFUN_MOUSE_MOTION: { // Mouse motion with right or middle mouse do nothing for now. if (cmd.button() != mouse_button::button1) { @@ -1229,7 +1411,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)); @@ -1319,6 +1501,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) cur.resetAnchor(); moveCursor(cur, false); + bv->bookmarkEditPosition(); break; } @@ -1365,12 +1548,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) docstring ds = cur.selectionAsString(false); cutSelection(cur, true, false); FuncRequest cmd0(cmd, ds); - inset = createInset(cur.bv().buffer(), cmd0); + inset = createInset(cur.buffer(), cmd0); } else { - inset = createInset(cur.bv().buffer(), cmd); + inset = createInset(cur.buffer(), cmd); } if (!inset) break; + cur.recordUndo(); insertInset(cur, inset); cur.posForward(); break; @@ -1381,18 +1565,20 @@ 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: case LFUN_OPTIONAL_INSERT: case LFUN_INDEX_INSERT: + case LFUN_PREVIEW_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()); + bv->buffer().updateBuffer(); break; case LFUN_TABULAR_INSERT: @@ -1425,7 +1611,7 @@ 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().setInsetOwner(&cur.text()->inset()); pars.back().setPlainOrDefaultLayout(tclass); int cap_pit = pars.size() - 1; @@ -1434,7 +1620,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) // the graphics (or table). if (!content) { pars.push_back(Paragraph()); - pars.back().setInsetOwner(&pars[0].inInset()); + pars.back().setInsetOwner(&cur.text()->inset()); pars.back().setPlainOrDefaultLayout(tclass); } @@ -1446,7 +1632,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) // date metrics. FuncRequest cmd_caption(LFUN_CAPTION_INSERT); doInsertInset(cur, cur.text(), cmd_caption, true, false); - updateLabels(bv->buffer()); + bv->buffer().updateBuffer(); cur.updateFlags(Update::Force); // FIXME: When leaving the Float (or Wrap) inset we should // delete any empty paragraph left above or below the @@ -1465,7 +1651,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: @@ -1487,6 +1684,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 @@ -1506,7 +1707,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) MacroType type = MacroTypeNewcommand; if (s2 == "def") type = MacroTypeDef; - MathMacroTemplate * inset = new MathMacroTemplate(from_utf8(token(s, ' ', 0)), nargs, false, type); + MathMacroTemplate * inset = new MathMacroTemplate(cur.buffer(), + from_utf8(token(s, ' ', 0)), nargs, false, type); inset->setBuffer(bv->buffer()); insertInset(cur, inset); @@ -1528,12 +1730,13 @@ 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: { cur.recordUndo(); cap::replaceSelection(cur); - cur.insert(new InsetMathHull(hullSimple)); + cur.insert(new InsetMathHull(cur.buffer(), hullSimple)); checkAndActivateInset(cur, true); LASSERT(cur.inMathed(), /**/); cur.dispatch(cmd); @@ -1547,6 +1750,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); @@ -1589,6 +1799,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); @@ -1702,7 +1933,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_ACCENT_HUNGARIAN_UMLAUT: case LFUN_ACCENT_CIRCLE: case LFUN_ACCENT_OGONEK: - theLyXFunc().handleKeyFunc(cmd.action); + theApp()->handleKeyFunc(cmd.action); if (!cmd.argument().empty()) // FIXME: Are all these characters encoded in one byte in utf8? bv->translateAndInsert(cmd.argument()[0], this, cur); @@ -1731,7 +1962,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) setParagraphs(cur, p); // FIXME This should be simplified when InsetFloatList takes a // Buffer in its constructor. - InsetFloatList * ifl = new InsetFloatList(to_utf8(cmd.argument())); + InsetFloatList * ifl = new InsetFloatList(cur.buffer(), to_utf8(cmd.argument())); ifl->setBuffer(bv->buffer()); insertInset(cur, ifl); cur.posForward(); @@ -1761,12 +1992,51 @@ 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)); break; } + case LFUN_SPELLING_ADD: { + docstring word = from_utf8(cmd.getArg(0)); + Language * lang; + if (word.empty()) { + word = cur.selectionAsString(false); + // FIXME + if (word.size() > 100 || word.empty()) { + // Get word or selection + selectWordWhenUnderCursor(cur, WHOLE_WORD); + word = cur.selectionAsString(false); + } + lang = const_cast(cur.getFont().language()); + } else + lang = const_cast(languages.getLanguage(cmd.getArg(1))); + WordLangTuple wl(word, lang); + theSpellChecker()->insert(wl); + break; + } + + case LFUN_SPELLING_IGNORE: { + docstring word = from_utf8(cmd.getArg(0)); + Language * lang; + if (word.empty()) { + word = cur.selectionAsString(false); + // FIXME + if (word.size() > 100 || word.empty()) { + // Get word or selection + selectWordWhenUnderCursor(cur, WHOLE_WORD); + word = cur.selectionAsString(false); + } + lang = const_cast(cur.getFont().language()); + } else + lang = const_cast(languages.getLanguage(cmd.getArg(1))); + WordLangTuple wl(word, lang); + theSpellChecker()->accept(wl); + break; + } + case LFUN_PARAGRAPH_PARAMS_APPLY: { // Given data, an encoding of the ParagraphParameters // generated in the Paragraph dialog, this function sets @@ -1803,26 +2073,26 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_OUTLINE_UP: outline(OutlineUp, cur); setCursor(cur, cur.pit(), 0); - updateLabels(cur.buffer()); + cur.buffer()->updateBuffer(); needsUpdate = true; break; case LFUN_OUTLINE_DOWN: outline(OutlineDown, cur); setCursor(cur, cur.pit(), 0); - updateLabels(cur.buffer()); + cur.buffer()->updateBuffer(); needsUpdate = true; break; case LFUN_OUTLINE_IN: outline(OutlineIn, cur); - updateLabels(cur.buffer()); + cur.buffer()->updateBuffer(); needsUpdate = true; break; case LFUN_OUTLINE_OUT: outline(OutlineOut, cur); - updateLabels(cur.buffer()); + cur.buffer()->updateBuffer(); needsUpdate = true; break; @@ -1857,7 +2127,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 // @@ -1900,8 +2170,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") @@ -1922,12 +2195,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") @@ -1961,18 +2240,60 @@ 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(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(cur.inset()); + enable = ins.params().type == to_utf8(cmd.argument()); + } + } break; case LFUN_WRAP_INSERT: code = WRAP_CODE; // not allowed in description items enable = !inDescriptionItem(cur); break; - case LFUN_FLOAT_LIST_INSERT: + case LFUN_FLOAT_LIST_INSERT: { code = FLOAT_LIST_CODE; + // not allowed in description items + enable = !inDescriptionItem(cur); + if (enable) { + FloatList const & floats = cur.buffer()->params().documentClass().floats(); + FloatList::const_iterator cit = floats[to_ascii(cmd.argument())]; + // make sure we know about such floats + if (cit == floats.end() || + // and that we know how to generate a list of them + (!cit->second.needsFloatPkg() && cit->second.listCommand().empty())) { + flag.unknown(true); + // probably not necessary, but... + enable = false; + } + } break; + } case LFUN_CAPTION_INSERT: code = CAPTION_CODE; // not allowed in description items @@ -1990,7 +2311,7 @@ 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)); + cur.buffer()->params().documentClass().insetLayout(from_utf8(s)); if (il.lyxtype() != InsetLayout::CHARSTYLE && il.lyxtype() != InsetLayout::CUSTOM && il.lyxtype() != InsetLayout::ELEMENT && @@ -2003,12 +2324,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; @@ -2022,6 +2350,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()) { @@ -2032,9 +2362,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()) { @@ -2055,6 +2389,27 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, if (cur.inTexted()) code = SPACE_CODE; break; + case LFUN_PREVIEW_INSERT: + code = PREVIEW_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_REGEXP_MODE: + code = MATH_HULL_CODE; + enable = cur.buffer()->isInternal() && !cur.inRegexped(); + break; case LFUN_INSET_MODIFY: // We need to disable this, because we may get called for a @@ -2066,27 +2421,38 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_FONT_EMPH: flag.setOnOff(fontinfo.emph() == FONT_ON); + enable = !cur.inset().getLayout().isPassThru(); + break; + + case LFUN_FONT_ITAL: + flag.setOnOff(fontinfo.shape() == ITALIC_SHAPE); + enable = !cur.inset().getLayout().isPassThru(); break; case LFUN_FONT_NOUN: flag.setOnOff(fontinfo.noun() == FONT_ON); + enable = !cur.inset().getLayout().isPassThru(); break; case LFUN_FONT_BOLD: case LFUN_FONT_BOLDSYMBOL: flag.setOnOff(fontinfo.series() == BOLD_SERIES); + enable = !cur.inset().getLayout().isPassThru(); break; case LFUN_FONT_SANS: flag.setOnOff(fontinfo.family() == SANS_FAMILY); + enable = !cur.inset().getLayout().isPassThru(); break; case LFUN_FONT_ROMAN: flag.setOnOff(fontinfo.family() == ROMAN_FAMILY); + enable = !cur.inset().getLayout().isPassThru(); break; case LFUN_FONT_TYPEWRITER: flag.setOnOff(fontinfo.family() == TYPEWRITER_FAMILY); + enable = !cur.inset().getLayout().isPassThru(); break; case LFUN_CUT: @@ -2113,11 +2479,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; } @@ -2134,6 +2503,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; @@ -2142,28 +2515,19 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, enable = cur.pit() < cur.lastpit() && !cur.selection(); break; - case LFUN_INSET_DISSOLVE: - if (!cmd.argument().empty()) { - InsetLayout const & il = cur.inset().getLayout(cur.buffer().params()); - InsetLayout::InsetLyXType const type = - translateLyXType(to_utf8(cmd.argument())); - enable = cur.inset().lyxCode() == FLEX_CODE - && il.lyxtype() == type; - } else { - enable = !isMainText(cur.bv().buffer()) - && cur.inset().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()) + enable = cur.paragraph().isChanged(cur.pos()); + else + // TODO: context-sensitive enabling of LFUN_CHANGE_ACCEPT/REJECT + // for selections. + enable = true; break; case LFUN_OUTLINE_UP: @@ -2171,7 +2535,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_OUTLINE_IN: case LFUN_OUTLINE_OUT: // FIXME: LyX is not ready for outlining within inset. - enable = isMainText(cur.bv().buffer()) + enable = isMainText() && cur.paragraph().layout().toclevel != Layout::NOT_IN_TOC; break; @@ -2180,6 +2544,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) @@ -2191,9 +2560,72 @@ 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(); + flag.setOnOff(to_utf8(cmd.argument()) == cur.real_current_font.language()->lang()); + break; + + case LFUN_BREAK_PARAGRAPH: + enable = cur.inset().getLayout().isMultiPar(); + break; + + case LFUN_SPELLING_ADD: + case LFUN_SPELLING_IGNORE: + enable = theSpellChecker(); + break; + + case LFUN_LAYOUT: + enable = !cur.inset().forcePlainLayout(); + break; + + case LFUN_LAYOUT_PARAGRAPH: + case LFUN_PARAGRAPH_PARAMS: + case LFUN_PARAGRAPH_PARAMS_APPLY: + case LFUN_PARAGRAPH_UPDATE: + enable = cur.inset().allowParagraphCustomization(); + break; + + // FIXME: why are accent lfuns forbidden with pass_thru layouts? + 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_FONT_DEFAULT: + case LFUN_FONT_FRAK: + 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_TEXTSTYLE_APPLY: + case LFUN_TEXTSTYLE_UPDATE: + enable = !cur.inset().getLayout().isPassThru(); + break; + case LFUN_WORD_DELETE_FORWARD: case LFUN_WORD_DELETE_BACKWARD: case LFUN_LINE_DELETE: @@ -2222,14 +2654,22 @@ 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_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_INSET_SELECT_ALL: 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: @@ -2238,52 +2678,10 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_SERVER_GET_XY: 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_SIZE: - case LFUN_LANGUAGE: - case LFUN_TEXTSTYLE_APPLY: - case LFUN_TEXTSTYLE_UPDATE: - case LFUN_LAYOUT_PARAGRAPH: - case LFUN_PARAGRAPH_UPDATE: - case LFUN_ACCENT_UMLAUT: - case LFUN_ACCENT_CIRCUMFLEX: - case LFUN_ACCENT_GRAVE: - case LFUN_ACCENT_ACUTE: - case LFUN_ACCENT_TILDE: - case LFUN_ACCENT_CEDILLA: - case LFUN_ACCENT_MACRON: - case LFUN_ACCENT_DOT: - case LFUN_ACCENT_UNDERDOT: - case LFUN_ACCENT_UNDERBAR: - case LFUN_ACCENT_CARON: - case LFUN_ACCENT_BREVE: - case LFUN_ACCENT_TIE: - case LFUN_ACCENT_HUNGARIAN_UMLAUT: - case LFUN_ACCENT_CIRCLE: - case LFUN_ACCENT_OGONEK: + case LFUN_UNICODE_INSERT: case LFUN_THESAURUS_ENTRY: - case LFUN_PARAGRAPH_PARAMS_APPLY: - case LFUN_PARAGRAPH_PARAMS: case LFUN_ESCAPE: - case LFUN_BUFFER_END: - case LFUN_BUFFER_BEGIN: - case LFUN_BUFFER_BEGIN_SELECT: - case LFUN_BUFFER_END_SELECT: - case LFUN_UNICODE_INSERT: // these are handled in our dispatch() enable = true; break; @@ -2293,7 +2691,9 @@ 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; flag.setEnabled(enable); @@ -2308,9 +2708,9 @@ void Text::pasteString(Cursor & cur, docstring const & clip, if (!clip.empty()) { cur.recordUndo(); if (asParagraphs) - insertStringAsParagraphs(cur, clip); + insertStringAsParagraphs(cur, clip, cur.current_font); else - insertStringAsLines(cur, clip); + insertStringAsLines(cur, clip, cur.current_font); } }