/**
- * \file text3.cpp
+ * \file Text3.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Asger Alstrup
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
* \author Alfredo Braunstein
* \author Angus Leeming
* \author John Levon
- * \author André Pönitz
+ * \author André Pönitz
*
* Full author contact details are available in file CREDITS.
*/
#include "TextMetrics.h"
#include "VSpace.h"
+#include "frontends/Application.h"
#include "frontends/Clipboard.h"
+#include "frontends/LyXView.h"
#include "frontends/Selection.h"
+#include "frontends/WorkArea.h"
#include "insets/InsetCollapsable.h"
#include "insets/InsetCommand.h"
+#include "insets/InsetExternal.h"
#include "insets/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 "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"
using cap::pasteClipboardText;
using cap::pasteClipboardGraphics;
using cap::replaceSelection;
+using cap::grabAndEraseSelection;
+using cap::selClearOrDel;
// globals...
static Font freefont(ignore_font, ignore_language);
istringstream is(selstr);
Lexer lex;
lex.setStream(is);
- formula->readQuiet(lex);
- if (formula->getType() == hullNone) {
+ if (!formula->readQuiet(lex)) {
// No valid formula, let's try with delims
is.str("$" + selstr + "$");
lex.setStream(is);
- formula->readQuiet(lex);
- if (formula->getType() == hullNone) {
+ if (!formula->readQuiet(lex)) {
// Still not valid, leave it as is
valid = false;
delete formula;
}
+void regexpDispatch(Cursor & cur, FuncRequest const & cmd)
+{
+ BOOST_ASSERT(cmd.action == LFUN_REGEXP_MODE);
+ if (cur.inRegexped()) {
+ cur.message(_("Already in regexp mode"));
+ return;
+ }
+ cur.recordUndo();
+ docstring const save_selection = grabAndEraseSelection(cur);
+ selClearOrDel(cur);
+ // replaceSelection(cur);
+
+ cur.insert(new InsetMathHull(hullRegexp));
+ cur.nextInset()->edit(cur, true);
+ cur.niceInsert(save_selection);
+
+ cur.message(_("Regexp editor mode"));
+}
+
+
static void specialChar(Cursor & cur, InsetSpecialChar::Kind kind)
{
cur.recordUndo();
if (!gotsel || !pastesel)
return true;
- pasteFromStack(cur, cur.buffer().errorList("Paste"), 0);
- cur.buffer().errors("Paste");
+ pasteFromStack(cur, cur.buffer()->errorList("Paste"), 0);
+ cur.buffer()->errors("Paste");
cur.clearSelection(); // bug 393
cur.finishUndo();
InsetText * insetText = dynamic_cast<InsetText *>(inset);
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();
BufferView * bv = &cur.bv();
TextMetrics & tm = bv->textMetrics(this);
- if (!tm.contains(cur.pit()))
- lyx::dispatch(FuncRequest(LFUN_SCREEN_RECENTER));
+ 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
recUndo(cur, pit, pit + 1);
cur.finishUndo();
swap(pars_[pit], pars_[pit + 1]);
- updateLabels(cur.buffer());
+ cur.buffer()->updateLabels();
needsUpdate = true;
++cur.pit();
break;
recUndo(cur, pit - 1, pit);
cur.finishUndo();
swap(pars_[pit], pars_[pit - 1]);
- updateLabels(cur.buffer());
+ cur.buffer()->updateLabels();
--cur.pit();
needsUpdate = true;
break;
par.params().startOfAppendix(start);
// we can set the refreshing parameters now
- updateLabels(cur.buffer());
+ cur.buffer()->updateLabels();
break;
}
case LFUN_WORD_DELETE_FORWARD:
- if (cur.selection()) {
+ if (cur.selection())
cutSelection(cur, true, false);
- } else
+ else
deleteWordForward(cur);
finishChange(cur, false);
break;
case LFUN_WORD_DELETE_BACKWARD:
- if (cur.selection()) {
+ if (cur.selection())
cutSelection(cur, true, false);
- } else
+ else
deleteWordBackward(cur);
finishChange(cur, false);
break;
case LFUN_LINE_DELETE:
- if (cur.selection()) {
+ if (cur.selection())
cutSelection(cur, true, false);
- } else
+ else
tm.deleteLineForward(cur);
finishChange(cur, false);
break;
case LFUN_BUFFER_BEGIN:
case LFUN_BUFFER_BEGIN_SELECT:
needsUpdate |= cur.selHandle(cmd.action == LFUN_BUFFER_BEGIN_SELECT);
- if (cur.depth() == 1) {
+ if (cur.depth() == 1)
needsUpdate |= cursorTop(cur);
- } else {
+ else
cur.undispatched();
- }
cur.updateFlags(Update::FitCursor);
break;
case LFUN_BUFFER_END:
case LFUN_BUFFER_END_SELECT:
needsUpdate |= cur.selHandle(cmd.action == LFUN_BUFFER_END_SELECT);
- if (cur.depth() == 1) {
+ if (cur.depth() == 1)
needsUpdate |= cursorBottom(cur);
- } else {
+ else
+ cur.undispatched();
+ cur.updateFlags(Update::FitCursor);
+ break;
+
+ case LFUN_INSET_BEGIN:
+ case LFUN_INSET_BEGIN_SELECT:
+ needsUpdate |= cur.selHandle(cmd.action == LFUN_INSET_BEGIN_SELECT);
+ if (cur.depth() == 1 || cur.pos() > 0)
+ needsUpdate |= cursorTop(cur);
+ else
+ cur.undispatched();
+ cur.updateFlags(Update::FitCursor);
+ break;
+
+ case LFUN_INSET_END:
+ case LFUN_INSET_END_SELECT:
+ needsUpdate |= cur.selHandle(cmd.action == LFUN_INSET_END_SELECT);
+ if (cur.depth() == 1 || cur.pos() < cur.lastpos())
+ needsUpdate |= cursorBottom(cur);
+ else
cur.undispatched();
- }
cur.updateFlags(Update::FitCursor);
break;
// 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;
}
case LFUN_INSET_INSERT: {
cur.recordUndo();
+
+ // We have to avoid triggering InstantPreview loading
+ // before inserting into the document. See bug #5626.
+ bool loaded = bv->buffer().isFullyLoaded();
+ bv->buffer().setFullyLoaded(false);
Inset * inset = createInset(bv->buffer(), cmd);
+ bv->buffer().setFullyLoaded(loaded);
+
if (inset) {
// FIXME (Abdel 01/02/2006):
// What follows would be a partial fix for bug 2154:
cutSelection(cur, true, false);
cur.insert(inset);
cur.posForward();
+
+ // trigger InstantPreview now
+ if (inset->lyxCode() == EXTERNAL_CODE) {
+ InsetExternal & ins =
+ static_cast<InsetExternal &>(*inset);
+ ins.updatePreview();
+ }
}
- break;
- }
- case LFUN_INSET_DISSOLVE:
- needsUpdate |= dissolveInset(cur);
break;
+ }
- case LFUN_INSET_SETTINGS: {
- Inset & inset = cur.inset();
- if (cmd.getArg(0) == insetName(inset.lyxCode())) {
- // This inset dialog has been explicitely requested.
- inset.showInsetDialog(bv);
- break;
+ case LFUN_INSET_DISSOLVE: {
+ // first, try if there's an inset at cursor
+ // FIXME: this first part should be moved to
+ // a LFUN_NEXT_INSET_DISSOLVE, or be called via
+ // some generic "next-inset inset-dissolve"
+ Inset * inset = cur.nextInset();
+ if (inset && inset->isActive()) {
+ Cursor tmpcur = cur;
+ tmpcur.pushBackward(*inset);
+ inset->dispatch(tmpcur, cmd);
+ if (tmpcur.result().dispatched()) {
+ cur.dispatched();
+ break;
+ }
}
- // else, if there is an inset at the cursor, access this
- Inset * next_inset = cur.nextInset();
- if (next_inset) {
- next_inset->showInsetDialog(bv);
+ // if it did not work, try the underlying inset
+ if (dissolveInset(cur)) {
+ needsUpdate = true;
break;
}
- // if not then access the underlying inset.
- inset.showInsetDialog(bv);
+ // if it did not work, do nothing.
break;
}
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"));
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;
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(bufparams);
+ if (!style.pass_thru && !ilayout.isPassThru()
&& par.getFontSettings(bufparams, pos).language()->lang() != "hebrew") {
// this avoids a double undo
// FIXME: should not be needed, ideally
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: {
cur.resetAnchor();
moveCursor(cur, false);
+ bv->bookmarkEditPosition();
break;
}
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:
cur.posForward();
// Some insets are numbered, others are shown in the outline pane so
// let's update the labels and the toc backend.
- updateLabels(bv->buffer());
+ bv->buffer().updateLabels();
break;
case LFUN_TABULAR_INSERT:
// date metrics.
FuncRequest cmd_caption(LFUN_CAPTION_INSERT);
doInsertInset(cur, cur.text(), cmd_caption, true, false);
- updateLabels(bv->buffer());
+ bv->buffer().updateLabels();
cur.updateFlags(Update::Force);
// FIXME: When leaving the Float (or Wrap) inset we should
// delete any empty paragraph left above or below the
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
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);
// 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));
case LFUN_OUTLINE_UP:
outline(OutlineUp, cur);
setCursor(cur, cur.pit(), 0);
- updateLabels(cur.buffer());
+ cur.buffer()->updateLabels();
needsUpdate = true;
break;
case LFUN_OUTLINE_DOWN:
outline(OutlineDown, cur);
setCursor(cur, cur.pit(), 0);
- updateLabels(cur.buffer());
+ cur.buffer()->updateLabels();
needsUpdate = true;
break;
case LFUN_OUTLINE_IN:
outline(OutlineIn, cur);
- updateLabels(cur.buffer());
+ cur.buffer()->updateLabels();
needsUpdate = true;
break;
case LFUN_OUTLINE_OUT:
outline(OutlineOut, cur);
- updateLabels(cur.buffer());
+ cur.buffer()->updateLabels();
needsUpdate = true;
break;
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")
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 &&
break;
case LFUN_BRANCH_INSERT:
code = BRANCH_CODE;
- if (cur.buffer().masterBuffer()->params().branchlist().empty())
+ if (cur.buffer()->masterBuffer()->params().branchlist().empty())
enable = false;
break;
+ case LFUN_PHANTOM_INSERT:
+ code = PHANTOM_CODE;
+ break;
case LFUN_LABEL_INSERT:
code = LABEL_CODE;
break;
flag.setOnOff(fontinfo.emph() == FONT_ON);
break;
+ case LFUN_FONT_ITAL:
+ flag.setOnOff(fontinfo.shape() == ITALIC_SHAPE);
+ break;
+
case LFUN_FONT_NOUN:
flag.setOnOff(fontinfo.noun() == FONT_ON);
break;
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;
case LFUN_INSET_DISSOLVE:
if (!cmd.argument().empty()) {
- InsetLayout const & il = cur.inset().getLayout(cur.buffer().params());
+ 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;
+ enable = ((!isMainText(cur.bv().buffer())
+ && cur.inset().nargs() == 1)
+ || (cur.nextInset()
+ && cur.nextInset()->nargs() == 1));
}
break;
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());
+ enable = support::os::is_valid_strftime(format);
+ break;
+ }
+
case LFUN_WORD_DELETE_FORWARD:
case LFUN_WORD_DELETE_BACKWARD:
case LFUN_LINE_DELETE:
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_PARAGRAPH_PARAMS_APPLY:
case LFUN_PARAGRAPH_PARAMS:
case LFUN_ESCAPE:
- case LFUN_BUFFER_END:
case LFUN_BUFFER_BEGIN:
+ case LFUN_BUFFER_END:
case LFUN_BUFFER_BEGIN_SELECT:
case LFUN_BUFFER_END_SELECT:
+ case LFUN_INSET_BEGIN:
+ case LFUN_INSET_END:
+ case LFUN_INSET_BEGIN_SELECT:
+ case LFUN_INSET_END_SELECT:
case LFUN_UNICODE_INSERT:
// these are handled in our dispatch()
enable = true;