3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup
7 * \author Lars Gullik Bjønnes
8 * \author Alfredo Braunstein
9 * \author Angus Leeming
11 * \author André Pönitz
13 * Full author contact details are available in file CREDITS.
21 #include "BranchList.h"
22 #include "FloatList.h"
23 #include "FuncStatus.h"
25 #include "buffer_funcs.h"
26 #include "BufferParams.h"
27 #include "BufferView.h"
29 #include "CutAndPaste.h"
30 #include "DispatchResult.h"
31 #include "ErrorList.h"
33 #include "FuncRequest.h"
34 #include "InsetList.h"
38 #include "LyXAction.h"
42 #include "Paragraph.h"
43 #include "paragraph_funcs.h"
44 #include "ParagraphParameters.h"
45 #include "TextClass.h"
46 #include "TextMetrics.h"
49 #include "frontends/Clipboard.h"
50 #include "frontends/Selection.h"
52 #include "insets/InsetCollapsable.h"
53 #include "insets/InsetCommand.h"
54 #include "insets/InsetFloatList.h"
55 #include "insets/InsetNewline.h"
56 #include "insets/InsetQuotes.h"
57 #include "insets/InsetSpecialChar.h"
58 #include "insets/InsetText.h"
59 #include "insets/InsetGraphics.h"
60 #include "insets/InsetGraphicsParams.h"
62 #include "support/convert.h"
63 #include "support/debug.h"
64 #include "support/gettext.h"
65 #include "support/lstrings.h"
66 #include "support/lyxtime.h"
68 #include "mathed/InsetMathHull.h"
69 #include "mathed/MathMacroTemplate.h"
71 #include <boost/next_prior.hpp>
77 using namespace lyx::support
;
81 using cap::copySelection
;
82 using cap::cutSelection
;
83 using cap::pasteFromStack
;
84 using cap::pasteClipboardText
;
85 using cap::pasteClipboardGraphics
;
86 using cap::replaceSelection
;
89 static Font
freefont(ignore_font
, ignore_language
);
90 static bool toggleall
= false;
92 static void toggleAndShow(Cursor
& cur
, Text
* text
,
93 Font
const & font
, bool toggleall
= true)
95 text
->toggleFree(cur
, font
, toggleall
);
97 if (font
.language() != ignore_language
||
98 font
.fontInfo().number() != FONT_IGNORE
) {
99 TextMetrics
const & tm
= cur
.bv().textMetrics(text
);
100 if (cur
.boundary() != tm
.isRTLBoundary(cur
.pit(), cur
.pos(),
101 cur
.real_current_font
))
102 text
->setCursor(cur
, cur
.pit(), cur
.pos(),
103 false, !cur
.boundary());
108 static void moveCursor(Cursor
& cur
, bool selecting
)
110 if (selecting
|| cur
.mark())
115 static void finishChange(Cursor
& cur
, bool selecting
)
118 moveCursor(cur
, selecting
);
122 static void mathDispatch(Cursor
& cur
, FuncRequest
const & cmd
, bool display
)
125 docstring sel
= cur
.selectionAsString(false);
127 // It may happen that sel is empty but there is a selection
128 replaceSelection(cur
);
130 // Is this a valid formula?
134 #ifdef ENABLE_ASSERTIONS
135 const int old_pos
= cur
.pos();
137 cur
.insert(new InsetMathHull(hullSimple
));
138 #ifdef ENABLE_ASSERTIONS
139 LASSERT(old_pos
== cur
.pos(), /**/);
141 cur
.nextInset()->edit(cur
, true);
142 // don't do that also for LFUN_MATH_MODE
143 // unless you want end up with always changing
144 // to mathrm when opening an inlined inset --
145 // I really hate "LyXfunc overloading"...
147 cur
.dispatch(FuncRequest(LFUN_MATH_DISPLAY
));
148 // Avoid an unnecessary undo step if cmd.argument
150 if (!cmd
.argument().empty())
151 cur
.dispatch(FuncRequest(LFUN_MATH_INSERT
,
154 // create a macro if we see "\\newcommand"
155 // somewhere, and an ordinary formula
157 if (sel
.find(from_ascii("\\newcommand")) == string::npos
158 && sel
.find(from_ascii("\\newlyxcommand")) == string::npos
159 && sel
.find(from_ascii("\\def")) == string::npos
)
161 InsetMathHull
* formula
= new InsetMathHull
;
162 string
const selstr
= to_utf8(sel
);
163 istringstream
is(selstr
);
166 formula
->readQuiet(lex
);
167 if (formula
->getType() == hullNone
) {
168 // No valid formula, let's try with delims
169 is
.str("$" + selstr
+ "$");
171 formula
->readQuiet(lex
);
172 if (formula
->getType() == hullNone
) {
173 // Still not valid, leave it as is
182 cur
.insert(new MathMacroTemplate(sel
));
186 cur
.message(from_utf8(N_("Math editor mode")));
188 cur
.message(from_utf8(N_("No valid math formula")));
192 static void specialChar(Cursor
& cur
, InsetSpecialChar::Kind kind
)
195 cap::replaceSelection(cur
);
196 cur
.insert(new InsetSpecialChar(kind
));
201 static bool doInsertInset(Cursor
& cur
, Text
* text
,
202 FuncRequest
const & cmd
, bool edit
, bool pastesel
)
204 Buffer
& buffer
= cur
.bv().buffer();
205 BufferParams
const & bparams
= buffer
.params();
206 Inset
* inset
= createInset(buffer
, cmd
);
210 if (InsetCollapsable
* ci
= inset
->asInsetCollapsable())
211 ci
->setLayout(bparams
);
214 if (cmd
.action
== LFUN_INDEX_INSERT
) {
215 docstring ds
= subst(text
->getStringToIndex(cur
), '\n', ' ');
216 text
->insertInset(cur
, inset
);
218 inset
->edit(cur
, true);
219 // Now put this into inset
220 static_cast<InsetCollapsable
*>(inset
)->text().insertStringAsParagraphs(cur
, ds
);
225 if (cur
.selection()) {
226 cutSelection(cur
, false, pastesel
);
227 cur
.clearSelection();
230 text
->insertInset(cur
, inset
);
233 inset
->edit(cur
, true);
235 if (!gotsel
|| !pastesel
)
238 pasteFromStack(cur
, cur
.buffer().errorList("Paste"), 0);
239 cur
.buffer().errors("Paste");
240 cur
.clearSelection(); // bug 393
242 InsetText
* insetText
= dynamic_cast<InsetText
*>(inset
);
243 if (insetText
&& (!insetText
->allowMultiPar() || cur
.lastpit() == 0)) {
244 // reset first par to default
245 cur
.text()->paragraphs().begin()
246 ->setPlainOrDefaultLayout(bparams
.documentClass());
249 // Merge multiple paragraphs -- hack
250 while (cur
.lastpit() > 0)
251 mergeParagraph(bparams
, cur
.text()->paragraphs(), 0);
252 cur
.leaveInset(*inset
);
254 cur
.leaveInset(*inset
);
255 // reset surrounding par to default
256 DocumentClass
const & dc
= bparams
.documentClass();
257 docstring
const layoutname
= inset
->usePlainLayout()
258 ? dc
.plainLayoutName()
259 : dc
.defaultLayoutName();
260 text
->setLayout(cur
, layoutname
);
267 string
const freefont2string()
269 return freefont
.toString(toggleall
);
273 /// the type of outline operation
275 OutlineUp
, // Move this header with text down
276 OutlineDown
, // Move this header with text up
277 OutlineIn
, // Make this header deeper
278 OutlineOut
// Make this header shallower
282 static void outline(OutlineOp mode
, Cursor
& cur
)
284 Buffer
& buf
= cur
.buffer();
285 pit_type
& pit
= cur
.pit();
286 ParagraphList
& pars
= buf
.text().paragraphs();
287 ParagraphList::iterator bgn
= pars
.begin();
288 // The first paragraph of the area to be copied:
289 ParagraphList::iterator start
= boost::next(bgn
, pit
);
290 // The final paragraph of area to be copied:
291 ParagraphList::iterator finish
= start
;
292 ParagraphList::iterator end
= pars
.end();
294 DocumentClass
const & tc
= buf
.params().documentClass();
296 int const thistoclevel
= start
->layout().toclevel
;
299 // Move out (down) from this section header
302 // Seek the one (on same level) below
303 for (; finish
!= end
; ++finish
) {
304 toclevel
= finish
->layout().toclevel
;
305 if (toclevel
!= Layout::NOT_IN_TOC
&& toclevel
<= thistoclevel
) {
312 if (start
== pars
.begin())
315 ParagraphList::iterator dest
= start
;
316 // Move out (up) from this header
319 // Search previous same-level header above
322 toclevel
= dest
->layout().toclevel
;
324 && (toclevel
== Layout::NOT_IN_TOC
325 || toclevel
> thistoclevel
));
326 // Not found; do nothing
327 if (toclevel
== Layout::NOT_IN_TOC
|| toclevel
> thistoclevel
)
329 pit_type
const newpit
= distance(bgn
, dest
);
330 pit_type
const len
= distance(start
, finish
);
331 pit_type
const deletepit
= pit
+ len
;
332 buf
.undo().recordUndo(cur
, ATOMIC_UNDO
, newpit
, deletepit
- 1);
333 pars
.insert(dest
, start
, finish
);
334 start
= boost::next(pars
.begin(), deletepit
);
336 pars
.erase(start
, finish
);
343 // Go one down from *this* header:
344 ParagraphList::iterator dest
= boost::next(finish
, 1);
345 // Go further down to find header to insert in front of:
346 for (; dest
!= end
; ++dest
) {
347 toclevel
= dest
->layout().toclevel
;
348 if (toclevel
!= Layout::NOT_IN_TOC
349 && toclevel
<= thistoclevel
) {
353 // One such was found:
354 pit_type newpit
= distance(bgn
, dest
);
355 pit_type
const len
= distance(start
, finish
);
356 buf
.undo().recordUndo(cur
, ATOMIC_UNDO
, pit
, newpit
- 1);
357 pars
.insert(dest
, start
, finish
);
358 start
= boost::next(bgn
, pit
);
360 pars
.erase(start
, finish
);
364 pit_type
const len
= distance(start
, finish
);
365 buf
.undo().recordUndo(cur
, ATOMIC_UNDO
, pit
, pit
+ len
- 1);
366 for (; start
!= finish
; ++start
) {
367 toclevel
= start
->layout().toclevel
;
368 if (toclevel
== Layout::NOT_IN_TOC
)
370 DocumentClass::const_iterator lit
= tc
.begin();
371 DocumentClass::const_iterator len
= tc
.end();
372 for (; lit
!= len
; ++lit
) {
373 if (lit
->toclevel
== toclevel
+ 1 &&
374 start
->layout().labeltype
== lit
->labeltype
) {
375 start
->setLayout(*lit
);
383 pit_type
const len
= distance(start
, finish
);
384 buf
.undo().recordUndo(cur
, ATOMIC_UNDO
, pit
, pit
+ len
- 1);
385 for (; start
!= finish
; ++start
) {
386 toclevel
= start
->layout().toclevel
;
387 if (toclevel
== Layout::NOT_IN_TOC
)
389 DocumentClass::const_iterator lit
= tc
.begin();
390 DocumentClass::const_iterator len
= tc
.end();
391 for (; lit
!= len
; ++lit
) {
392 if (lit
->toclevel
== toclevel
- 1 &&
393 start
->layout().labeltype
== lit
->labeltype
) {
394 start
->setLayout(*lit
);
405 void Text::number(Cursor
& cur
)
407 FontInfo font
= ignore_font
;
408 font
.setNumber(FONT_TOGGLE
);
409 toggleAndShow(cur
, this, Font(font
, ignore_language
));
413 bool Text::isRTL(Buffer
const & buffer
, Paragraph
const & par
) const
415 return par
.isRTL(buffer
.params());
419 void Text::dispatch(Cursor
& cur
, FuncRequest
& cmd
)
421 LYXERR(Debug::ACTION
, "Text::dispatch: cmd: " << cmd
);
423 BufferView
* bv
= &cur
.bv();
424 TextMetrics
& tm
= bv
->textMetrics(this);
425 if (!tm
.contains(cur
.pit()))
426 lyx::dispatch(FuncRequest(LFUN_SCREEN_RECENTER
));
428 // FIXME: We use the update flag to indicates wether a singlePar or a
429 // full screen update is needed. We reset it here but shall we restore it
433 LASSERT(cur
.text() == this, /**/);
434 CursorSlice oldTopSlice
= cur
.top();
435 bool oldBoundary
= cur
.boundary();
436 bool sel
= cur
.selection();
437 // Signals that, even if needsUpdate == false, an update of the
438 // cursor paragraph is required
439 bool singleParUpdate
= lyxaction
.funcHasFlag(cmd
.action
,
440 LyXAction::SingleParUpdate
);
441 // Signals that a full-screen update is required
442 bool needsUpdate
= !(lyxaction
.funcHasFlag(cmd
.action
,
443 LyXAction::NoUpdate
) || singleParUpdate
);
445 switch (cmd
.action
) {
447 case LFUN_PARAGRAPH_MOVE_DOWN
: {
448 pit_type
const pit
= cur
.pit();
449 recUndo(cur
, pit
, pit
+ 1);
451 swap(pars_
[pit
], pars_
[pit
+ 1]);
452 updateLabels(cur
.buffer());
458 case LFUN_PARAGRAPH_MOVE_UP
: {
459 pit_type
const pit
= cur
.pit();
460 recUndo(cur
, pit
- 1, pit
);
462 swap(pars_
[pit
], pars_
[pit
- 1]);
463 updateLabels(cur
.buffer());
469 case LFUN_APPENDIX
: {
470 Paragraph
& par
= cur
.paragraph();
471 bool start
= !par
.params().startOfAppendix();
473 // FIXME: The code below only makes sense at top level.
474 // Should LFUN_APPENDIX be restricted to top-level paragraphs?
475 // ensure that we have only one start_of_appendix in this document
476 // FIXME: this don't work for multipart document!
477 for (pit_type tmp
= 0, end
= pars_
.size(); tmp
!= end
; ++tmp
) {
478 if (pars_
[tmp
].params().startOfAppendix()) {
480 pars_
[tmp
].params().startOfAppendix(false);
486 par
.params().startOfAppendix(start
);
488 // we can set the refreshing parameters now
489 updateLabels(cur
.buffer());
493 case LFUN_WORD_DELETE_FORWARD
:
494 if (cur
.selection()) {
495 cutSelection(cur
, true, false);
497 deleteWordForward(cur
);
498 finishChange(cur
, false);
501 case LFUN_WORD_DELETE_BACKWARD
:
502 if (cur
.selection()) {
503 cutSelection(cur
, true, false);
505 deleteWordBackward(cur
);
506 finishChange(cur
, false);
509 case LFUN_LINE_DELETE
:
510 if (cur
.selection()) {
511 cutSelection(cur
, true, false);
513 tm
.deleteLineForward(cur
);
514 finishChange(cur
, false);
517 case LFUN_BUFFER_BEGIN
:
518 case LFUN_BUFFER_BEGIN_SELECT
:
519 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_BUFFER_BEGIN_SELECT
);
520 if (cur
.depth() == 1) {
521 needsUpdate
|= cursorTop(cur
);
525 cur
.updateFlags(Update::FitCursor
);
528 case LFUN_BUFFER_END
:
529 case LFUN_BUFFER_END_SELECT
:
530 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_BUFFER_END_SELECT
);
531 if (cur
.depth() == 1) {
532 needsUpdate
|= cursorBottom(cur
);
536 cur
.updateFlags(Update::FitCursor
);
539 case LFUN_CHAR_FORWARD
:
540 case LFUN_CHAR_FORWARD_SELECT
:
541 //LYXERR0(" LFUN_CHAR_FORWARD[SEL]:\n" << cur);
542 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_CHAR_FORWARD_SELECT
);
543 needsUpdate
|= cursorForward(cur
);
545 if (!needsUpdate
&& oldTopSlice
== cur
.top()
546 && cur
.boundary() == oldBoundary
) {
548 cmd
= FuncRequest(LFUN_FINISHED_FORWARD
);
552 case LFUN_CHAR_BACKWARD
:
553 case LFUN_CHAR_BACKWARD_SELECT
:
554 //lyxerr << "handle LFUN_CHAR_BACKWARD[_SELECT]:\n" << cur << endl;
555 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_CHAR_BACKWARD_SELECT
);
556 needsUpdate
|= cursorBackward(cur
);
558 if (!needsUpdate
&& oldTopSlice
== cur
.top()
559 && cur
.boundary() == oldBoundary
) {
561 cmd
= FuncRequest(LFUN_FINISHED_BACKWARD
);
566 case LFUN_CHAR_LEFT_SELECT
:
567 if (lyxrc
.visual_cursor
) {
568 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_CHAR_LEFT_SELECT
);
569 needsUpdate
|= cursorVisLeft(cur
);
570 if (!needsUpdate
&& oldTopSlice
== cur
.top()
571 && cur
.boundary() == oldBoundary
) {
573 cmd
= FuncRequest(LFUN_FINISHED_LEFT
);
576 if (reverseDirectionNeeded(cur
)) {
577 cmd
.action
= cmd
.action
== LFUN_CHAR_LEFT_SELECT
?
578 LFUN_CHAR_FORWARD_SELECT
: LFUN_CHAR_FORWARD
;
580 cmd
.action
= cmd
.action
== LFUN_CHAR_LEFT_SELECT
?
581 LFUN_CHAR_BACKWARD_SELECT
: LFUN_CHAR_BACKWARD
;
588 case LFUN_CHAR_RIGHT
:
589 case LFUN_CHAR_RIGHT_SELECT
:
590 if (lyxrc
.visual_cursor
) {
591 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_CHAR_RIGHT_SELECT
);
592 needsUpdate
|= cursorVisRight(cur
);
593 if (!needsUpdate
&& oldTopSlice
== cur
.top()
594 && cur
.boundary() == oldBoundary
) {
596 cmd
= FuncRequest(LFUN_FINISHED_RIGHT
);
599 if (reverseDirectionNeeded(cur
)) {
600 cmd
.action
= cmd
.action
== LFUN_CHAR_RIGHT_SELECT
?
601 LFUN_CHAR_BACKWARD_SELECT
: LFUN_CHAR_BACKWARD
;
603 cmd
.action
= cmd
.action
== LFUN_CHAR_RIGHT_SELECT
?
604 LFUN_CHAR_FORWARD_SELECT
: LFUN_CHAR_FORWARD
;
613 case LFUN_DOWN_SELECT
:
616 // stop/start the selection
617 bool select
= cmd
.action
== LFUN_DOWN_SELECT
||
618 cmd
.action
== LFUN_UP_SELECT
;
619 cur
.selHandle(select
);
621 // move cursor up/down
622 bool up
= cmd
.action
== LFUN_UP_SELECT
|| cmd
.action
== LFUN_UP
;
623 bool const successful
= cur
.upDownInText(up
, needsUpdate
);
625 // redraw if you leave mathed (for the decorations)
626 needsUpdate
|= cur
.beforeDispatchCursor().inMathed();
633 case LFUN_PARAGRAPH_UP
:
634 case LFUN_PARAGRAPH_UP_SELECT
:
635 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_PARAGRAPH_UP_SELECT
);
636 needsUpdate
|= cursorUpParagraph(cur
);
639 case LFUN_PARAGRAPH_DOWN
:
640 case LFUN_PARAGRAPH_DOWN_SELECT
:
641 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_PARAGRAPH_DOWN_SELECT
);
642 needsUpdate
|= cursorDownParagraph(cur
);
645 case LFUN_LINE_BEGIN
:
646 case LFUN_LINE_BEGIN_SELECT
:
647 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_LINE_BEGIN_SELECT
);
648 needsUpdate
|= tm
.cursorHome(cur
);
652 case LFUN_LINE_END_SELECT
:
653 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_LINE_END_SELECT
);
654 needsUpdate
|= tm
.cursorEnd(cur
);
657 case LFUN_WORD_RIGHT
:
658 case LFUN_WORD_RIGHT_SELECT
:
659 if (lyxrc
.visual_cursor
) {
660 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_WORD_RIGHT_SELECT
);
661 needsUpdate
|= cursorVisRightOneWord(cur
);
662 if (!needsUpdate
&& oldTopSlice
== cur
.top()
663 && cur
.boundary() == oldBoundary
) {
665 cmd
= FuncRequest(LFUN_FINISHED_RIGHT
);
668 if (reverseDirectionNeeded(cur
)) {
669 cmd
.action
= cmd
.action
== LFUN_WORD_RIGHT_SELECT
?
670 LFUN_WORD_BACKWARD_SELECT
: LFUN_WORD_BACKWARD
;
672 cmd
.action
= cmd
.action
== LFUN_WORD_RIGHT_SELECT
?
673 LFUN_WORD_FORWARD_SELECT
: LFUN_WORD_FORWARD
;
680 case LFUN_WORD_FORWARD
:
681 case LFUN_WORD_FORWARD_SELECT
:
682 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_WORD_FORWARD_SELECT
);
683 needsUpdate
|= cursorForwardOneWord(cur
);
687 case LFUN_WORD_LEFT_SELECT
:
688 if (lyxrc
.visual_cursor
) {
689 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_WORD_LEFT_SELECT
);
690 needsUpdate
|= cursorVisLeftOneWord(cur
);
691 if (!needsUpdate
&& oldTopSlice
== cur
.top()
692 && cur
.boundary() == oldBoundary
) {
694 cmd
= FuncRequest(LFUN_FINISHED_LEFT
);
697 if (reverseDirectionNeeded(cur
)) {
698 cmd
.action
= cmd
.action
== LFUN_WORD_LEFT_SELECT
?
699 LFUN_WORD_FORWARD_SELECT
: LFUN_WORD_FORWARD
;
701 cmd
.action
= cmd
.action
== LFUN_WORD_LEFT_SELECT
?
702 LFUN_WORD_BACKWARD_SELECT
: LFUN_WORD_BACKWARD
;
709 case LFUN_WORD_BACKWARD
:
710 case LFUN_WORD_BACKWARD_SELECT
:
711 needsUpdate
|= cur
.selHandle(cmd
.action
== LFUN_WORD_BACKWARD_SELECT
);
712 needsUpdate
|= cursorBackwardOneWord(cur
);
715 case LFUN_WORD_SELECT
: {
716 selectWord(cur
, WHOLE_WORD
);
717 finishChange(cur
, true);
721 case LFUN_NEWLINE_INSERT
: {
722 InsetNewlineParams inp
;
723 docstring arg
= cmd
.argument();
724 // this avoids a double undo
725 // FIXME: should not be needed, ideally
726 if (!cur
.selection())
728 cap::replaceSelection(cur
);
729 if (arg
== "linebreak")
730 inp
.kind
= InsetNewlineParams::LINEBREAK
;
732 inp
.kind
= InsetNewlineParams::NEWLINE
;
733 cur
.insert(new InsetNewline(inp
));
735 moveCursor(cur
, false);
739 case LFUN_CHAR_DELETE_FORWARD
:
740 if (!cur
.selection()) {
741 if (cur
.pos() == cur
.paragraph().size())
742 // Par boundary, force full-screen update
743 singleParUpdate
= false;
744 needsUpdate
|= erase(cur
);
746 // It is possible to make it a lot faster still
747 // just comment out the line below...
749 cutSelection(cur
, true, false);
750 singleParUpdate
= false;
752 moveCursor(cur
, false);
755 case LFUN_CHAR_DELETE_BACKWARD
:
756 if (!cur
.selection()) {
757 if (bv
->getIntl().getTransManager().backspace()) {
758 // Par boundary, full-screen update
760 singleParUpdate
= false;
761 needsUpdate
|= backspace(cur
);
763 // It is possible to make it a lot faster still
764 // just comment out the line below...
767 cutSelection(cur
, true, false);
768 singleParUpdate
= false;
772 case LFUN_BREAK_PARAGRAPH
:
773 cap::replaceSelection(cur
);
774 breakParagraph(cur
, cmd
.argument() == "inverse");
779 // With the creation of LFUN_PARAGRAPH_PARAMS, this is now redundant,
780 // as its duties can be performed there. Should it be removed??
781 // FIXME For now, it can just dispatch LFUN_PARAGRAPH_PARAMS...
782 case LFUN_PARAGRAPH_SPACING
: {
783 Paragraph
& par
= cur
.paragraph();
784 Spacing::Space cur_spacing
= par
.params().spacing().getSpace();
785 string cur_value
= "1.0";
786 if (cur_spacing
== Spacing::Other
)
787 cur_value
= par
.params().spacing().getValueAsString();
789 istringstream
is(to_utf8(cmd
.argument()));
792 Spacing::Space new_spacing
= cur_spacing
;
793 string new_value
= cur_value
;
795 lyxerr
<< "Missing argument to `paragraph-spacing'"
797 } else if (tmp
== "single") {
798 new_spacing
= Spacing::Single
;
799 } else if (tmp
== "onehalf") {
800 new_spacing
= Spacing::Onehalf
;
801 } else if (tmp
== "double") {
802 new_spacing
= Spacing::Double
;
803 } else if (tmp
== "other") {
804 new_spacing
= Spacing::Other
;
805 string tmpval
= "0.0";
807 lyxerr
<< "new_value = " << tmpval
<< endl
;
810 } else if (tmp
== "default") {
811 new_spacing
= Spacing::Default
;
813 lyxerr
<< to_utf8(_("Unknown spacing argument: "))
814 << to_utf8(cmd
.argument()) << endl
;
816 if (cur_spacing
!= new_spacing
|| cur_value
!= new_value
)
817 par
.params().spacing(Spacing(new_spacing
, new_value
));
821 case LFUN_INSET_INSERT
: {
823 Inset
* inset
= createInset(bv
->buffer(), cmd
);
825 // FIXME (Abdel 01/02/2006):
826 // What follows would be a partial fix for bug 2154:
827 // http://bugzilla.lyx.org/show_bug.cgi?id=2154
828 // This automatically put the label inset _after_ a
829 // numbered section. It should be possible to extend the mechanism
830 // to any kind of LateX environement.
831 // The correct way to fix that bug would be at LateX generation.
832 // I'll let the code here for reference as it could be used for some
833 // other feature like "automatic labelling".
835 Paragraph & par = pars_[cur.pit()];
836 if (inset->lyxCode() == LABEL_CODE
837 && par.layout().labeltype == LABEL_COUNTER) {
838 // Go to the end of the paragraph
839 // Warning: Because of Change-Tracking, the last
840 // position is 'size()' and not 'size()-1':
841 cur.pos() = par.size();
842 // Insert a new paragraph
843 FuncRequest fr(LFUN_BREAK_PARAGRAPH);
848 cutSelection(cur
, true, false);
855 case LFUN_INSET_DISSOLVE
:
856 needsUpdate
|= dissolveInset(cur
);
859 case LFUN_INSET_SETTINGS
: {
860 Inset
& inset
= cur
.inset();
861 if (cmd
.getArg(0) == insetName(inset
.lyxCode())) {
862 // This inset dialog has been explicitely requested.
863 inset
.showInsetDialog(bv
);
866 // else, if there is an inset at the cursor, access this
867 Inset
* next_inset
= cur
.nextInset();
869 next_inset
->showInsetDialog(bv
);
872 // if not then access the underlying inset.
873 inset
.showInsetDialog(bv
);
877 case LFUN_SET_GRAPHICS_GROUP
: {
878 InsetGraphics
* ins
= graphics::getCurrentGraphicsInset(cur
);
884 string id
= to_utf8(cmd
.argument());
885 string grp
= graphics::getGroupParams(bv
->buffer(), id
);
886 InsetGraphicsParams tmp
, inspar
= ins
->getParams();
889 inspar
.groupId
= to_utf8(cmd
.argument());
891 InsetGraphics::string2params(grp
, bv
->buffer(), tmp
);
892 tmp
.filename
= inspar
.filename
;
896 ins
->setParams(inspar
);
899 case LFUN_SPACE_INSERT
:
900 if (cur
.paragraph().layout().free_spacing
)
901 insertChar(cur
, ' ');
903 doInsertInset(cur
, this, cmd
, false, false);
906 moveCursor(cur
, false);
909 case LFUN_SPECIALCHAR_INSERT
: {
910 string
const name
= to_utf8(cmd
.argument());
911 if (name
== "hyphenation")
912 specialChar(cur
, InsetSpecialChar::HYPHENATION
);
913 else if (name
== "ligature-break")
914 specialChar(cur
, InsetSpecialChar::LIGATURE_BREAK
);
915 else if (name
== "slash")
916 specialChar(cur
, InsetSpecialChar::SLASH
);
917 else if (name
== "nobreakdash")
918 specialChar(cur
, InsetSpecialChar::NOBREAKDASH
);
919 else if (name
== "dots")
920 specialChar(cur
, InsetSpecialChar::LDOTS
);
921 else if (name
== "end-of-sentence")
922 specialChar(cur
, InsetSpecialChar::END_OF_SENTENCE
);
923 else if (name
== "menu-separator")
924 specialChar(cur
, InsetSpecialChar::MENU_SEPARATOR
);
925 else if (name
.empty())
926 lyxerr
<< "LyX function 'specialchar-insert' needs an argument." << endl
;
928 lyxerr
<< "Wrong argument for LyX function 'specialchar-insert'." << endl
;
932 case LFUN_WORD_UPCASE
:
933 changeCase(cur
, text_uppercase
);
936 case LFUN_WORD_LOWCASE
:
937 changeCase(cur
, text_lowercase
);
940 case LFUN_WORD_CAPITALIZE
:
941 changeCase(cur
, text_capitalization
);
944 case LFUN_CHARS_TRANSPOSE
:
949 cur
.message(_("Paste"));
950 LASSERT(cur
.selBegin().idx() == cur
.selEnd().idx(), /**/);
951 cap::replaceSelection(cur
);
954 string
const arg
= to_utf8(cmd
.argument());
956 if (theClipboard().isInternal())
957 pasteFromStack(cur
, bv
->buffer().errorList("Paste"), 0);
958 else if (theClipboard().hasGraphicsContents())
959 pasteClipboardGraphics(cur
, bv
->buffer().errorList("Paste"));
961 pasteClipboardText(cur
, bv
->buffer().errorList("Paste"));
962 } else if (isStrUnsignedInt(arg
)) {
963 // we have a numerical argument
964 pasteFromStack(cur
, bv
->buffer().errorList("Paste"),
965 convert
<unsigned int>(arg
));
967 Clipboard::GraphicsType type
= Clipboard::AnyGraphicsType
;
969 type
= Clipboard::PdfGraphicsType
;
970 else if (arg
== "png")
971 type
= Clipboard::PngGraphicsType
;
972 else if (arg
== "jpeg")
973 type
= Clipboard::JpegGraphicsType
;
974 else if (arg
== "linkback")
975 type
= Clipboard::LinkBackGraphicsType
;
977 LASSERT(false, /**/);
979 pasteClipboardGraphics(cur
, bv
->buffer().errorList("Paste"), type
);
982 bv
->buffer().errors("Paste");
983 cur
.clearSelection(); // bug 393
989 cutSelection(cur
, true, true);
990 cur
.message(_("Cut"));
995 cur
.message(_("Copy"));
998 case LFUN_SERVER_GET_XY
:
999 cur
.message(from_utf8(
1000 convert
<string
>(tm
.cursorX(cur
.top(), cur
.boundary()))
1001 + ' ' + convert
<string
>(tm
.cursorY(cur
.top(), cur
.boundary()))));
1004 case LFUN_SERVER_SET_XY
: {
1007 istringstream
is(to_utf8(cmd
.argument()));
1010 lyxerr
<< "SETXY: Could not parse coordinates in '"
1011 << to_utf8(cmd
.argument()) << endl
;
1013 tm
.setCursorFromCoordinates(cur
, x
, y
);
1017 case LFUN_SERVER_GET_LAYOUT
:
1018 cur
.message(cur
.paragraph().layout().name());
1022 docstring layout
= cmd
.argument();
1023 LYXERR(Debug::INFO
, "LFUN_LAYOUT: (arg) " << to_utf8(layout
));
1025 Paragraph
const & para
= cur
.paragraph();
1026 docstring
const old_layout
= para
.layout().name();
1027 DocumentClass
const & tclass
= bv
->buffer().params().documentClass();
1030 layout
= tclass
.defaultLayoutName();
1032 if (para
.forcePlainLayout())
1033 // in this case only the empty layout is allowed
1034 layout
= tclass
.plainLayoutName();
1035 else if (para
.usePlainLayout()) {
1036 // in this case, default layout maps to empty layout
1037 if (layout
== tclass
.defaultLayoutName())
1038 layout
= tclass
.plainLayoutName();
1040 // otherwise, the empty layout maps to the default
1041 if (layout
== tclass
.plainLayoutName())
1042 layout
= tclass
.defaultLayoutName();
1045 bool hasLayout
= tclass
.hasLayout(layout
);
1047 // If the entry is obsolete, use the new one instead.
1049 docstring
const & obs
= tclass
[layout
].obsoleted_by();
1055 cur
.errorMessage(from_utf8(N_("Layout ")) + cmd
.argument() +
1056 from_utf8(N_(" not known")));
1060 bool change_layout
= (old_layout
!= layout
);
1062 if (!change_layout
&& cur
.selection() &&
1063 cur
.selBegin().pit() != cur
.selEnd().pit())
1065 pit_type spit
= cur
.selBegin().pit();
1066 pit_type epit
= cur
.selEnd().pit() + 1;
1067 while (spit
!= epit
) {
1068 if (pars_
[spit
].layout().name() != old_layout
) {
1069 change_layout
= true;
1077 setLayout(cur
, layout
);
1082 case LFUN_CLIPBOARD_PASTE
:
1083 cur
.clearSelection();
1084 pasteClipboardText(cur
, bv
->buffer().errorList("Paste"),
1085 cmd
.argument() == "paragraph");
1086 bv
->buffer().errors("Paste");
1089 case LFUN_PRIMARY_SELECTION_PASTE
:
1090 pasteString(cur
, theSelection().get(),
1091 cmd
.argument() == "paragraph");
1094 case LFUN_UNICODE_INSERT
: {
1095 if (cmd
.argument().empty())
1097 docstring hexstring
= cmd
.argument();
1098 if (isHex(hexstring
)) {
1099 char_type c
= hexToInt(hexstring
);
1100 if (c
>= 32 && c
< 0x10ffff) {
1101 lyxerr
<< "Inserting c: " << c
<< endl
;
1102 docstring s
= docstring(1, c
);
1103 lyx::dispatch(FuncRequest(LFUN_SELF_INSERT
, s
));
1109 case LFUN_QUOTE_INSERT
: {
1110 Paragraph
& par
= cur
.paragraph();
1111 pos_type pos
= cur
.pos();
1112 BufferParams
const & bufparams
= bv
->buffer().params();
1113 Layout
const & style
= par
.layout();
1114 if (!style
.pass_thru
1115 && par
.getFontSettings(bufparams
, pos
).language()->lang() != "hebrew") {
1116 // this avoids a double undo
1117 // FIXME: should not be needed, ideally
1118 if (!cur
.selection())
1120 cap::replaceSelection(cur
);
1125 else if (cur
.prevInset() && cur
.prevInset()->isSpace())
1128 c
= par
.getChar(pos
- 1);
1129 string arg
= to_utf8(cmd
.argument());
1130 cur
.insert(new InsetQuotes(bv
->buffer(), c
, (arg
== "single")
1131 ? InsetQuotes::SingleQuotes
: InsetQuotes::DoubleQuotes
));
1135 lyx::dispatch(FuncRequest(LFUN_SELF_INSERT
, "\""));
1139 case LFUN_DATE_INSERT
: {
1140 string
const format
= cmd
.argument().empty()
1141 ? lyxrc
.date_insert_format
: to_utf8(cmd
.argument());
1142 string
const time
= formatted_time(current_time(), format
);
1143 lyx::dispatch(FuncRequest(LFUN_SELF_INSERT
, time
));
1147 case LFUN_MOUSE_TRIPLE
:
1148 if (cmd
.button() == mouse_button::button1
) {
1157 case LFUN_MOUSE_DOUBLE
:
1158 if (cmd
.button() == mouse_button::button1
) {
1159 selectWord(cur
, WHOLE_WORD_STRICT
);
1164 // Single-click on work area
1165 case LFUN_MOUSE_PRESS
:
1166 // We are not marking a selection with the keyboard in any case.
1167 cur
.bv().cursor().setMark(false);
1168 switch (cmd
.button()) {
1169 case mouse_button::button1
:
1171 if (!bv
->mouseSetCursor(cur
, cmd
.argument() == "region-select"))
1172 cur
.updateFlags(Update::SinglePar
| Update::FitCursor
);
1175 case mouse_button::button2
:
1176 // Middle mouse pasting.
1177 bv
->mouseSetCursor(cur
);
1178 if (!cap::selection()) {
1179 // There is no local selection in the current buffer, so try to
1180 // paste primary selection instead.
1181 lyx::dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE
,
1183 // Nothing else to do.
1187 // Copy the selection buffer to the clipboard stack, because we want it
1188 // to appear in the "Edit->Paste recent" menu.
1189 cap::copySelectionToStack();
1190 cap::pasteSelection(bv
->cursor(), bv
->buffer().errorList("Paste"));
1191 cur
.updateFlags(Update::Force
| Update::FitCursor
);
1192 bv
->buffer().errors("Paste");
1193 bv
->buffer().markDirty();
1194 bv
->cursor().finishUndo();
1197 case mouse_button::button3
: {
1198 Cursor
const & bvcur
= cur
.bv().cursor();
1199 // Don't do anything if we right-click a
1200 // selection, a context menu will popup.
1201 if (bvcur
.selection() && cur
>= bvcur
.selectionBegin()
1202 && cur
< bvcur
.selectionEnd()) {
1206 if (!bv
->mouseSetCursor(cur
, false))
1207 cur
.updateFlags(Update::SinglePar
| Update::FitCursor
);
1213 } // switch (cmd.button())
1216 case LFUN_MOUSE_MOTION
: {
1217 // Mouse motion with right or middle mouse do nothing for now.
1218 if (cmd
.button() != mouse_button::button1
) {
1222 // ignore motions deeper nested than the real anchor
1223 Cursor
& bvcur
= cur
.bv().cursor();
1224 if (!bvcur
.anchor_
.hasPart(cur
)) {
1228 CursorSlice old
= bvcur
.top();
1230 int const wh
= bv
->workHeight();
1231 int const y
= max(0, min(wh
- 1, cmd
.y
));
1233 tm
.setCursorFromCoordinates(cur
, cmd
.x
, y
);
1234 cur
.setTargetX(cmd
.x
);
1236 lyx::dispatch(FuncRequest(LFUN_DOWN_SELECT
));
1238 lyx::dispatch(FuncRequest(LFUN_UP_SELECT
));
1239 // This is to allow jumping over large insets
1240 if (cur
.top() == old
) {
1242 lyx::dispatch(FuncRequest(LFUN_DOWN_SELECT
));
1244 lyx::dispatch(FuncRequest(LFUN_UP_SELECT
));
1246 // We continue with our existing selection or start a new one, so don't
1247 // reset the anchor.
1248 bvcur
.setCursor(cur
);
1249 bvcur
.setSelection(true);
1250 if (cur
.top() == old
) {
1251 // We didn't move one iota, so no need to update the screen.
1252 cur
.updateFlags(Update::SinglePar
| Update::FitCursor
);
1259 case LFUN_MOUSE_RELEASE
:
1260 switch (cmd
.button()) {
1261 case mouse_button::button1
:
1262 // Cursor was set at LFUN_MOUSE_PRESS or LFUN_MOUSE_MOTION time.
1263 // If there is a new selection, update persistent selection;
1264 // otherwise, single click does not clear persistent selection
1266 if (cur
.selection()) {
1267 // Finish selection. If double click,
1268 // cur is moved to the end of word by
1269 // selectWord but bvcur is current
1271 cur
.bv().cursor().setSelection();
1272 // We might have removed an empty but drawn selection
1273 // (probably a margin)
1274 cur
.updateFlags(Update::SinglePar
| Update::FitCursor
);
1277 // FIXME: We could try to handle drag and drop of selection here.
1280 case mouse_button::button2
:
1281 // Middle mouse pasting is handled at mouse press time,
1282 // see LFUN_MOUSE_PRESS.
1286 case mouse_button::button3
:
1287 // Cursor was set at LFUN_MOUSE_PRESS time.
1288 // FIXME: If there is a selection we could try to handle a special
1289 // drag & drop context menu.
1293 case mouse_button::none
:
1294 case mouse_button::button4
:
1295 case mouse_button::button5
:
1297 } // switch (cmd.button())
1301 case LFUN_SELF_INSERT
: {
1302 if (cmd
.argument().empty())
1305 // Automatically delete the currently selected
1306 // text and replace it with what is being
1307 // typed in now. Depends on lyxrc settings
1308 // "auto_region_delete", which defaults to
1311 if (lyxrc
.auto_region_delete
&& cur
.selection())
1312 cutSelection(cur
, false, false);
1314 cur
.clearSelection();
1316 docstring::const_iterator cit
= cmd
.argument().begin();
1317 docstring::const_iterator
const end
= cmd
.argument().end();
1318 for (; cit
!= end
; ++cit
)
1319 bv
->translateAndInsert(*cit
, this, cur
);
1322 moveCursor(cur
, false);
1326 case LFUN_HYPERLINK_INSERT
: {
1327 InsetCommandParams
p(HYPERLINK_CODE
);
1329 if (cur
.selection()) {
1330 content
= cur
.selectionAsString(false);
1331 cutSelection(cur
, true, false);
1333 p
["target"] = (cmd
.argument().empty()) ?
1334 content
: cmd
.argument();
1335 string
const data
= InsetCommand::params2string("href", p
);
1336 if (p
["target"].empty()) {
1337 bv
->showDialog("href", data
);
1339 FuncRequest
fr(LFUN_INSET_INSERT
, data
);
1345 case LFUN_LABEL_INSERT
: {
1346 InsetCommandParams
p(LABEL_CODE
);
1347 // Try to generate a valid label
1348 p
["name"] = (cmd
.argument().empty()) ?
1349 cur
.getPossibleLabel() :
1351 string
const data
= InsetCommand::params2string("label", p
);
1353 if (cmd
.argument().empty()) {
1354 bv
->showDialog("label", data
);
1356 FuncRequest
fr(LFUN_INSET_INSERT
, data
);
1362 case LFUN_INFO_INSERT
: {
1364 if (cmd
.argument().empty() && cur
.selection()) {
1365 // if command argument is empty use current selection as parameter.
1366 docstring ds
= cur
.selectionAsString(false);
1367 cutSelection(cur
, true, false);
1368 FuncRequest
cmd0(cmd
, ds
);
1369 inset
= createInset(cur
.bv().buffer(), cmd0
);
1371 inset
= createInset(cur
.bv().buffer(), cmd
);
1375 insertInset(cur
, inset
);
1379 case LFUN_CAPTION_INSERT
:
1380 case LFUN_FOOTNOTE_INSERT
:
1381 case LFUN_NOTE_INSERT
:
1382 case LFUN_FLEX_INSERT
:
1383 case LFUN_BOX_INSERT
:
1384 case LFUN_BRANCH_INSERT
:
1385 case LFUN_ERT_INSERT
:
1386 case LFUN_LISTING_INSERT
:
1387 case LFUN_MARGINALNOTE_INSERT
:
1388 case LFUN_OPTIONAL_INSERT
:
1389 case LFUN_INDEX_INSERT
:
1390 // Open the inset, and move the current selection
1392 doInsertInset(cur
, this, cmd
, true, true);
1394 // Some insets are numbered, others are shown in the outline pane so
1395 // let's update the labels and the toc backend.
1396 updateLabels(bv
->buffer());
1399 case LFUN_TABULAR_INSERT
:
1400 // if there were no arguments, just open the dialog
1401 if (doInsertInset(cur
, this, cmd
, false, true))
1404 bv
->showDialog("tabularcreate");
1408 case LFUN_FLOAT_INSERT
:
1409 case LFUN_FLOAT_WIDE_INSERT
:
1410 case LFUN_WRAP_INSERT
: {
1411 bool content
= cur
.selection(); // will some text be moved into the inset?
1413 doInsertInset(cur
, this, cmd
, true, true);
1415 ParagraphList
& pars
= cur
.text()->paragraphs();
1417 DocumentClass
const & tclass
= bv
->buffer().params().documentClass();
1419 // add a separate paragraph for the caption inset
1420 pars
.push_back(Paragraph());
1421 pars
.back().setInsetOwner(&pars
[0].inInset());
1422 pars
.back().setPlainOrDefaultLayout(tclass
);
1423 int cap_pit
= pars
.size() - 1;
1425 // if an empty inset was created, we create an additional empty
1426 // paragraph at the bottom so that the user can choose where to put
1427 // the graphics (or table).
1429 pars
.push_back(Paragraph());
1430 pars
.back().setInsetOwner(&pars
[0].inInset());
1431 pars
.back().setPlainOrDefaultLayout(tclass
);
1434 // reposition the cursor to the caption
1435 cur
.pit() = cap_pit
;
1437 // FIXME: This Text/Cursor dispatch handling is a mess!
1438 // We cannot use Cursor::dispatch here it needs access to up to
1440 FuncRequest
cmd_caption(LFUN_CAPTION_INSERT
);
1441 cur
.text()->dispatch(cur
, cmd_caption
);
1442 cur
.updateFlags(Update::Force
);
1443 // FIXME: When leaving the Float (or Wrap) inset we should
1444 // delete any empty paragraph left above or below the
1449 case LFUN_NOMENCL_INSERT
: {
1450 InsetCommandParams
p(NOMENCL_CODE
);
1451 if (cmd
.argument().empty())
1452 p
["symbol"] = bv
->cursor().innerText()->getStringToIndex(bv
->cursor());
1454 p
["symbol"] = cmd
.argument();
1455 string
const data
= InsetCommand::params2string("nomenclature", p
);
1456 bv
->showDialog("nomenclature", data
);
1460 case LFUN_INDEX_PRINT
:
1461 case LFUN_NOMENCL_PRINT
:
1462 case LFUN_TOC_INSERT
:
1463 case LFUN_LINE_INSERT
:
1464 case LFUN_NEWPAGE_INSERT
:
1466 doInsertInset(cur
, this, cmd
, false, false);
1470 case LFUN_DEPTH_DECREMENT
:
1471 changeDepth(cur
, DEC_DEPTH
);
1474 case LFUN_DEPTH_INCREMENT
:
1475 changeDepth(cur
, INC_DEPTH
);
1478 case LFUN_MATH_DISPLAY
:
1479 mathDispatch(cur
, cmd
, true);
1482 case LFUN_MATH_MODE
:
1483 if (cmd
.argument() == "on")
1484 // don't pass "on" as argument
1485 mathDispatch(cur
, FuncRequest(LFUN_MATH_MODE
), false);
1487 mathDispatch(cur
, cmd
, false);
1490 case LFUN_MATH_MACRO
:
1491 if (cmd
.argument().empty())
1492 cur
.errorMessage(from_utf8(N_("Missing argument")));
1494 string s
= to_utf8(cmd
.argument());
1495 string
const s1
= token(s
, ' ', 1);
1496 int const nargs
= s1
.empty() ? 0 : convert
<int>(s1
);
1497 string
const s2
= token(s
, ' ', 2);
1498 MacroType type
= MacroTypeNewcommand
;
1500 type
= MacroTypeDef
;
1501 MathMacroTemplate
* inset
= new MathMacroTemplate(from_utf8(token(s
, ' ', 0)), nargs
, false, type
);
1502 inset
->setBuffer(bv
->buffer());
1503 insertInset(cur
, inset
);
1505 // enter macro inset and select the name
1507 cur
.top().pos() = cur
.top().lastpos();
1509 cur
.setSelection(true);
1510 cur
.top().pos() = 0;
1514 // passthrough hat and underscore outside mathed:
1515 case LFUN_MATH_SUBSCRIPT
:
1516 mathDispatch(cur
, FuncRequest(LFUN_SELF_INSERT
, "_"), false);
1518 case LFUN_MATH_SUPERSCRIPT
:
1519 mathDispatch(cur
, FuncRequest(LFUN_SELF_INSERT
, "^"), false);
1522 case LFUN_MATH_INSERT
:
1523 case LFUN_MATH_MATRIX
:
1524 case LFUN_MATH_DELIM
:
1525 case LFUN_MATH_BIGDELIM
: {
1527 cap::replaceSelection(cur
);
1528 cur
.insert(new InsetMathHull(hullSimple
));
1529 checkAndActivateInset(cur
, true);
1530 LASSERT(cur
.inMathed(), /**/);
1535 case LFUN_FONT_EMPH
: {
1536 Font
font(ignore_font
, ignore_language
);
1537 font
.fontInfo().setEmph(FONT_TOGGLE
);
1538 toggleAndShow(cur
, this, font
);
1542 case LFUN_FONT_BOLD
:
1543 case LFUN_FONT_BOLDSYMBOL
: {
1544 Font
font(ignore_font
, ignore_language
);
1545 font
.fontInfo().setSeries(BOLD_SERIES
);
1546 toggleAndShow(cur
, this, font
);
1550 case LFUN_FONT_NOUN
: {
1551 Font
font(ignore_font
, ignore_language
);
1552 font
.fontInfo().setNoun(FONT_TOGGLE
);
1553 toggleAndShow(cur
, this, font
);
1557 case LFUN_FONT_TYPEWRITER
: {
1558 Font
font(ignore_font
, ignore_language
);
1559 font
.fontInfo().setFamily(TYPEWRITER_FAMILY
); // no good
1560 toggleAndShow(cur
, this, font
);
1564 case LFUN_FONT_SANS
: {
1565 Font
font(ignore_font
, ignore_language
);
1566 font
.fontInfo().setFamily(SANS_FAMILY
);
1567 toggleAndShow(cur
, this, font
);
1571 case LFUN_FONT_ROMAN
: {
1572 Font
font(ignore_font
, ignore_language
);
1573 font
.fontInfo().setFamily(ROMAN_FAMILY
);
1574 toggleAndShow(cur
, this, font
);
1578 case LFUN_FONT_DEFAULT
: {
1579 Font
font(inherit_font
, ignore_language
);
1580 toggleAndShow(cur
, this, font
);
1584 case LFUN_FONT_UNDERLINE
: {
1585 Font
font(ignore_font
, ignore_language
);
1586 font
.fontInfo().setUnderbar(FONT_TOGGLE
);
1587 toggleAndShow(cur
, this, font
);
1591 case LFUN_FONT_SIZE
: {
1592 Font
font(ignore_font
, ignore_language
);
1593 setLyXSize(to_utf8(cmd
.argument()), font
.fontInfo());
1594 toggleAndShow(cur
, this, font
);
1598 case LFUN_LANGUAGE
: {
1599 Language
const * lang
= languages
.getLanguage(to_utf8(cmd
.argument()));
1602 Font
font(ignore_font
, lang
);
1603 toggleAndShow(cur
, this, font
);
1607 case LFUN_TEXTSTYLE_APPLY
:
1608 toggleAndShow(cur
, this, freefont
, toggleall
);
1609 cur
.message(_("Character set"));
1612 // Set the freefont using the contents of \param data dispatched from
1613 // the frontends and apply it at the current cursor location.
1614 case LFUN_TEXTSTYLE_UPDATE
: {
1617 if (font
.fromString(to_utf8(cmd
.argument()), toggle
)) {
1620 toggleAndShow(cur
, this, freefont
, toggleall
);
1621 cur
.message(_("Character set"));
1623 lyxerr
<< "Argument not ok";
1628 case LFUN_FINISHED_LEFT
:
1629 LYXERR(Debug::DEBUG
, "handle LFUN_FINISHED_LEFT:\n" << cur
);
1630 // We're leaving an inset, going left. If the inset is LTR, we're
1631 // leaving from the front, so we should not move (remain at --- but
1632 // not in --- the inset). If the inset is RTL, move left, without
1633 // entering the inset itself; i.e., move to after the inset.
1634 if (cur
.paragraph().getFontSettings(
1635 cur
.bv().buffer().params(), cur
.pos()).isRightToLeft())
1636 cursorVisLeft(cur
, true);
1639 case LFUN_FINISHED_RIGHT
:
1640 LYXERR(Debug::DEBUG
, "handle LFUN_FINISHED_RIGHT:\n" << cur
);
1641 // We're leaving an inset, going right. If the inset is RTL, we're
1642 // leaving from the front, so we should not move (remain at --- but
1643 // not in --- the inset). If the inset is LTR, move right, without
1644 // entering the inset itself; i.e., move to after the inset.
1645 if (!cur
.paragraph().getFontSettings(
1646 cur
.bv().buffer().params(), cur
.pos()).isRightToLeft())
1647 cursorVisRight(cur
, true);
1650 case LFUN_FINISHED_BACKWARD
:
1651 LYXERR(Debug::DEBUG
, "handle LFUN_FINISHED_BACKWARD:\n" << cur
);
1654 case LFUN_FINISHED_FORWARD
:
1655 LYXERR(Debug::DEBUG
, "handle LFUN_FINISHED_FORWARD:\n" << cur
);
1657 cur
.setCurrentFont();
1660 case LFUN_LAYOUT_PARAGRAPH
: {
1662 params2string(cur
.paragraph(), data
);
1663 data
= "show\n" + data
;
1664 bv
->showDialog("paragraph", data
);
1668 case LFUN_PARAGRAPH_UPDATE
: {
1670 params2string(cur
.paragraph(), data
);
1672 // Will the paragraph accept changes from the dialog?
1674 cur
.inset().allowParagraphCustomization(cur
.idx());
1676 data
= "update " + convert
<string
>(accept
) + '\n' + data
;
1677 bv
->updateDialog("paragraph", data
);
1681 case LFUN_ACCENT_UMLAUT
:
1682 case LFUN_ACCENT_CIRCUMFLEX
:
1683 case LFUN_ACCENT_GRAVE
:
1684 case LFUN_ACCENT_ACUTE
:
1685 case LFUN_ACCENT_TILDE
:
1686 case LFUN_ACCENT_CEDILLA
:
1687 case LFUN_ACCENT_MACRON
:
1688 case LFUN_ACCENT_DOT
:
1689 case LFUN_ACCENT_UNDERDOT
:
1690 case LFUN_ACCENT_UNDERBAR
:
1691 case LFUN_ACCENT_CARON
:
1692 case LFUN_ACCENT_BREVE
:
1693 case LFUN_ACCENT_TIE
:
1694 case LFUN_ACCENT_HUNGARIAN_UMLAUT
:
1695 case LFUN_ACCENT_CIRCLE
:
1696 case LFUN_ACCENT_OGONEK
:
1697 theLyXFunc().handleKeyFunc(cmd
.action
);
1698 if (!cmd
.argument().empty())
1699 // FIXME: Are all these characters encoded in one byte in utf8?
1700 bv
->translateAndInsert(cmd
.argument()[0], this, cur
);
1703 case LFUN_FLOAT_LIST_INSERT
: {
1704 DocumentClass
const & tclass
= bv
->buffer().params().documentClass();
1705 if (tclass
.floats().typeExist(to_utf8(cmd
.argument()))) {
1707 if (cur
.selection())
1708 cutSelection(cur
, true, false);
1709 breakParagraph(cur
);
1711 if (cur
.lastpos() != 0) {
1712 cursorBackward(cur
);
1713 breakParagraph(cur
);
1716 docstring
const laystr
= cur
.inset().usePlainLayout() ?
1717 tclass
.plainLayoutName() :
1718 tclass
.defaultLayoutName();
1719 setLayout(cur
, laystr
);
1720 ParagraphParameters p
;
1721 // FIXME If this call were replaced with one to clearParagraphParams(),
1722 // then we could get rid of this method altogether.
1723 setParagraphs(cur
, p
);
1724 // FIXME This should be simplified when InsetFloatList takes a
1725 // Buffer in its constructor.
1726 InsetFloatList
* ifl
= new InsetFloatList(to_utf8(cmd
.argument()));
1727 ifl
->setBuffer(bv
->buffer());
1728 insertInset(cur
, ifl
);
1731 lyxerr
<< "Non-existent float type: "
1732 << to_utf8(cmd
.argument()) << endl
;
1737 case LFUN_CHANGE_ACCEPT
: {
1738 acceptOrRejectChanges(cur
, ACCEPT
);
1742 case LFUN_CHANGE_REJECT
: {
1743 acceptOrRejectChanges(cur
, REJECT
);
1747 case LFUN_THESAURUS_ENTRY
: {
1748 docstring arg
= cmd
.argument();
1750 arg
= cur
.selectionAsString(false);
1752 if (arg
.size() > 100 || arg
.empty()) {
1753 // Get word or selection
1754 selectWordWhenUnderCursor(cur
, WHOLE_WORD
);
1755 arg
= cur
.selectionAsString(false);
1758 bv
->showDialog("thesaurus", to_utf8(arg
));
1762 case LFUN_PARAGRAPH_PARAMS_APPLY
: {
1763 // Given data, an encoding of the ParagraphParameters
1764 // generated in the Paragraph dialog, this function sets
1765 // the current paragraph, or currently selected paragraphs,
1767 // NOTE: This function overrides all existing settings.
1768 setParagraphs(cur
, cmd
.argument());
1769 cur
.message(_("Paragraph layout set"));
1773 case LFUN_PARAGRAPH_PARAMS
: {
1774 // Given data, an encoding of the ParagraphParameters as we'd
1775 // find them in a LyX file, this function modifies the current paragraph,
1776 // or currently selected paragraphs.
1777 // NOTE: This function only modifies, and does not override, existing
1779 setParagraphs(cur
, cmd
.argument(), true);
1780 cur
.message(_("Paragraph layout set"));
1785 if (cur
.selection()) {
1786 cur
.setSelection(false);
1789 // This used to be LFUN_FINISHED_RIGHT, I think FORWARD is more
1790 // correct, but I'm not 100% sure -- dov, 071019
1791 cmd
= FuncRequest(LFUN_FINISHED_FORWARD
);
1795 case LFUN_OUTLINE_UP
:
1796 outline(OutlineUp
, cur
);
1797 setCursor(cur
, cur
.pit(), 0);
1798 updateLabels(cur
.buffer());
1802 case LFUN_OUTLINE_DOWN
:
1803 outline(OutlineDown
, cur
);
1804 setCursor(cur
, cur
.pit(), 0);
1805 updateLabels(cur
.buffer());
1809 case LFUN_OUTLINE_IN
:
1810 outline(OutlineIn
, cur
);
1811 updateLabels(cur
.buffer());
1815 case LFUN_OUTLINE_OUT
:
1816 outline(OutlineOut
, cur
);
1817 updateLabels(cur
.buffer());
1822 LYXERR(Debug::ACTION
, "Command " << cmd
<< " not DISPATCHED by Text");
1827 needsUpdate
|= (cur
.pos() != cur
.lastpos()) && cur
.selection();
1829 // FIXME: The cursor flag is reset two lines below
1830 // so we need to check here if some of the LFUN did touch that.
1831 // for now only Text::erase() and Text::backspace() do that.
1832 // The plan is to verify all the LFUNs and then to remove this
1833 // singleParUpdate boolean altogether.
1834 if (cur
.result().update() & Update::Force
) {
1835 singleParUpdate
= false;
1839 // FIXME: the following code should go in favor of fine grained
1840 // update flag treatment.
1841 if (singleParUpdate
) {
1842 // Inserting characters does not change par height in general. So, try
1843 // to update _only_ this paragraph. BufferView will detect if a full
1844 // metrics update is needed anyway.
1845 cur
.updateFlags(Update::SinglePar
| Update::FitCursor
);
1850 && &oldTopSlice
.inset() == &cur
.inset()
1851 && oldTopSlice
.idx() == cur
.idx()
1852 && !sel
// sel is a backup of cur.selection() at the biginning of the function.
1853 && !cur
.selection())
1854 // FIXME: it would be better if we could just do this
1856 //if (cur.result().update() != Update::FitCursor)
1859 // But some LFUNs do not set Update::FitCursor when needed, so we
1860 // do it for all. This is not very harmfull as FitCursor will provoke
1861 // a full redraw only if needed but still, a proper review of all LFUN
1862 // should be done and this needsUpdate boolean can then be removed.
1863 cur
.updateFlags(Update::FitCursor
);
1865 cur
.updateFlags(Update::Force
| Update::FitCursor
);
1869 bool Text::getStatus(Cursor
& cur
, FuncRequest
const & cmd
,
1870 FuncStatus
& flag
) const
1872 LASSERT(cur
.text() == this, /**/);
1874 FontInfo
const & fontinfo
= cur
.real_current_font
.fontInfo();
1876 InsetCode code
= NO_CODE
;
1878 switch (cmd
.action
) {
1880 case LFUN_DEPTH_DECREMENT
:
1881 enable
= changeDepthAllowed(cur
, DEC_DEPTH
);
1884 case LFUN_DEPTH_INCREMENT
:
1885 enable
= changeDepthAllowed(cur
, INC_DEPTH
);
1889 flag
.setOnOff(cur
.paragraph().params().startOfAppendix());
1892 case LFUN_DIALOG_SHOW_NEW_INSET
:
1893 if (cmd
.argument() == "bibitem")
1894 code
= BIBITEM_CODE
;
1895 else if (cmd
.argument() == "bibtex")
1897 else if (cmd
.argument() == "box")
1899 else if (cmd
.argument() == "branch")
1901 else if (cmd
.argument() == "citation")
1903 else if (cmd
.argument() == "ert")
1905 else if (cmd
.argument() == "external")
1906 code
= EXTERNAL_CODE
;
1907 else if (cmd
.argument() == "float")
1909 else if (cmd
.argument() == "graphics")
1910 code
= GRAPHICS_CODE
;
1911 else if (cmd
.argument() == "href")
1912 code
= HYPERLINK_CODE
;
1913 else if (cmd
.argument() == "include")
1914 code
= INCLUDE_CODE
;
1915 else if (cmd
.argument() == "index")
1917 else if (cmd
.argument() == "nomenclature")
1918 code
= NOMENCL_CODE
;
1919 else if (cmd
.argument() == "label")
1921 else if (cmd
.argument() == "note")
1923 else if (cmd
.argument() == "ref")
1925 else if (cmd
.argument() == "space")
1927 else if (cmd
.argument() == "toc")
1929 else if (cmd
.argument() == "vspace")
1931 else if (cmd
.argument() == "wrap")
1933 else if (cmd
.argument() == "listings")
1934 code
= LISTINGS_CODE
;
1937 case LFUN_ERT_INSERT
:
1940 case LFUN_LISTING_INSERT
:
1941 code
= LISTINGS_CODE
;
1942 // not allowed in description items
1943 enable
= !inDescriptionItem(cur
);
1945 case LFUN_FOOTNOTE_INSERT
:
1948 case LFUN_TABULAR_INSERT
:
1949 code
= TABULAR_CODE
;
1951 case LFUN_MARGINALNOTE_INSERT
:
1954 case LFUN_FLOAT_INSERT
:
1955 case LFUN_FLOAT_WIDE_INSERT
:
1957 // not allowed in description items
1958 enable
= !inDescriptionItem(cur
);
1960 case LFUN_WRAP_INSERT
:
1962 // not allowed in description items
1963 enable
= !inDescriptionItem(cur
);
1965 case LFUN_FLOAT_LIST_INSERT
:
1966 code
= FLOAT_LIST_CODE
;
1968 case LFUN_CAPTION_INSERT
:
1969 code
= CAPTION_CODE
;
1970 // not allowed in description items
1971 enable
= !inDescriptionItem(cur
);
1973 case LFUN_NOTE_INSERT
:
1975 // in commands (sections etc.) and description items,
1976 // only Notes are allowed
1977 enable
= (cmd
.argument().empty() || cmd
.getArg(0) == "Note" ||
1978 (!cur
.paragraph().layout().isCommand()
1979 && !inDescriptionItem(cur
)));
1981 case LFUN_FLEX_INSERT
: {
1983 string s
= cmd
.getArg(0);
1985 cur
.buffer().params().documentClass().insetLayout(from_utf8(s
));
1986 if (il
.lyxtype() != "charstyle" &&
1987 il
.lyxtype() != "custom" &&
1988 il
.lyxtype() != "element" &&
1989 il
.lyxtype ()!= "standard")
1993 case LFUN_BOX_INSERT
:
1996 case LFUN_BRANCH_INSERT
:
1998 if (cur
.buffer().masterBuffer()->params().branchlist().empty())
2001 case LFUN_LABEL_INSERT
:
2004 case LFUN_INFO_INSERT
:
2007 case LFUN_OPTIONAL_INSERT
:
2009 enable
= cur
.paragraph().insetList().count(OPTARG_CODE
)
2010 < cur
.paragraph().layout().optionalargs
;
2012 case LFUN_INDEX_INSERT
:
2015 case LFUN_INDEX_PRINT
:
2016 code
= INDEX_PRINT_CODE
;
2018 case LFUN_NOMENCL_INSERT
:
2019 if (cur
.selIsMultiCell() || cur
.selIsMultiLine()) {
2023 code
= NOMENCL_CODE
;
2025 case LFUN_NOMENCL_PRINT
:
2026 code
= NOMENCL_PRINT_CODE
;
2028 case LFUN_TOC_INSERT
:
2031 case LFUN_HYPERLINK_INSERT
:
2032 if (cur
.selIsMultiCell() || cur
.selIsMultiLine()) {
2036 code
= HYPERLINK_CODE
;
2038 case LFUN_QUOTE_INSERT
:
2039 // always allow this, since we will inset a raw quote
2040 // if an inset is not allowed.
2042 case LFUN_SPECIALCHAR_INSERT
:
2043 code
= SPECIALCHAR_CODE
;
2045 case LFUN_SPACE_INSERT
:
2046 // slight hack: we know this is allowed in math mode
2051 case LFUN_INSET_MODIFY
:
2052 // We need to disable this, because we may get called for a
2054 // InsetTabular::getStatus() -> InsetText::getStatus()
2055 // and we don't handle LFUN_INSET_MODIFY.
2059 case LFUN_FONT_EMPH
:
2060 flag
.setOnOff(fontinfo
.emph() == FONT_ON
);
2063 case LFUN_FONT_NOUN
:
2064 flag
.setOnOff(fontinfo
.noun() == FONT_ON
);
2067 case LFUN_FONT_BOLD
:
2068 case LFUN_FONT_BOLDSYMBOL
:
2069 flag
.setOnOff(fontinfo
.series() == BOLD_SERIES
);
2072 case LFUN_FONT_SANS
:
2073 flag
.setOnOff(fontinfo
.family() == SANS_FAMILY
);
2076 case LFUN_FONT_ROMAN
:
2077 flag
.setOnOff(fontinfo
.family() == ROMAN_FAMILY
);
2080 case LFUN_FONT_TYPEWRITER
:
2081 flag
.setOnOff(fontinfo
.family() == TYPEWRITER_FAMILY
);
2086 enable
= cur
.selection();
2090 if (cmd
.argument().empty()) {
2091 if (theClipboard().isInternal())
2092 enable
= cap::numberOfSelections() > 0;
2094 enable
= !theClipboard().empty();
2098 // we have an argument
2099 string
const arg
= to_utf8(cmd
.argument());
2100 if (isStrUnsignedInt(arg
)) {
2101 // it's a number and therefore means the internal stack
2102 unsigned int n
= convert
<unsigned int>(arg
);
2103 enable
= cap::numberOfSelections() > n
;
2107 // explicit graphics type?
2108 if ((arg
== "pdf" && theClipboard().hasGraphicsContents(Clipboard::PdfGraphicsType
))
2109 || (arg
== "png" && theClipboard().hasGraphicsContents(Clipboard::PngGraphicsType
))
2110 || (arg
== "jpeg" && theClipboard().hasGraphicsContents(Clipboard::JpegGraphicsType
))
2111 || (arg
== "linkback" && theClipboard().hasGraphicsContents(Clipboard::LinkBackGraphicsType
))) {
2121 case LFUN_CLIPBOARD_PASTE
:
2122 enable
= !theClipboard().empty();
2125 case LFUN_PRIMARY_SELECTION_PASTE
:
2126 enable
= cur
.selection() || !theSelection().empty();
2129 case LFUN_PARAGRAPH_MOVE_UP
:
2130 enable
= cur
.pit() > 0 && !cur
.selection();
2133 case LFUN_PARAGRAPH_MOVE_DOWN
:
2134 enable
= cur
.pit() < cur
.lastpit() && !cur
.selection();
2137 case LFUN_INSET_DISSOLVE
:
2138 if (!cmd
.argument().empty()) {
2139 InsetLayout il
= cur
.inset().getLayout(cur
.buffer().params());
2140 enable
= cur
.inset().lyxCode() == FLEX_CODE
2141 && il
.lyxtype() == to_utf8(cmd
.argument());
2143 enable
= !isMainText(cur
.bv().buffer())
2144 && cur
.inset().nargs() == 1;
2148 case LFUN_CHANGE_ACCEPT
:
2149 case LFUN_CHANGE_REJECT
:
2150 // TODO: context-sensitive enabling of LFUN_CHANGE_ACCEPT/REJECT
2151 // In principle, these LFUNs should only be enabled if there
2152 // is a change at the current position/in the current selection.
2153 // However, without proper optimizations, this will inevitably
2154 // result in unacceptable performance - just imagine a user who
2155 // wants to select the complete content of a long document.
2159 case LFUN_OUTLINE_UP
:
2160 case LFUN_OUTLINE_DOWN
:
2161 case LFUN_OUTLINE_IN
:
2162 case LFUN_OUTLINE_OUT
:
2163 // FIXME: LyX is not ready for outlining within inset.
2164 enable
= isMainText(cur
.bv().buffer())
2165 && cur
.paragraph().layout().toclevel
!= Layout::NOT_IN_TOC
;
2168 case LFUN_NEWLINE_INSERT
:
2169 // LaTeX restrictions (labels or empty par)
2170 enable
= (cur
.pos() > cur
.paragraph().beginOfBody());
2173 case LFUN_SET_GRAPHICS_GROUP
: {
2174 InsetGraphics
* ins
= graphics::getCurrentGraphicsInset(cur
);
2178 flag
.setOnOff(to_utf8(cmd
.argument()) == ins
->getParams().groupId
);
2182 case LFUN_NEWPAGE_INSERT
:
2183 // not allowed in description items
2184 enable
= !inDescriptionItem(cur
);
2187 case LFUN_WORD_DELETE_FORWARD
:
2188 case LFUN_WORD_DELETE_BACKWARD
:
2189 case LFUN_LINE_DELETE
:
2190 case LFUN_WORD_FORWARD
:
2191 case LFUN_WORD_BACKWARD
:
2192 case LFUN_WORD_RIGHT
:
2193 case LFUN_WORD_LEFT
:
2194 case LFUN_CHAR_FORWARD
:
2195 case LFUN_CHAR_FORWARD_SELECT
:
2196 case LFUN_CHAR_BACKWARD
:
2197 case LFUN_CHAR_BACKWARD_SELECT
:
2198 case LFUN_CHAR_LEFT
:
2199 case LFUN_CHAR_LEFT_SELECT
:
2200 case LFUN_CHAR_RIGHT
:
2201 case LFUN_CHAR_RIGHT_SELECT
:
2203 case LFUN_UP_SELECT
:
2205 case LFUN_DOWN_SELECT
:
2206 case LFUN_PARAGRAPH_UP_SELECT
:
2207 case LFUN_PARAGRAPH_DOWN_SELECT
:
2208 case LFUN_LINE_BEGIN_SELECT
:
2209 case LFUN_LINE_END_SELECT
:
2210 case LFUN_WORD_FORWARD_SELECT
:
2211 case LFUN_WORD_BACKWARD_SELECT
:
2212 case LFUN_WORD_RIGHT_SELECT
:
2213 case LFUN_WORD_LEFT_SELECT
:
2214 case LFUN_WORD_SELECT
:
2215 case LFUN_PARAGRAPH_UP
:
2216 case LFUN_PARAGRAPH_DOWN
:
2217 case LFUN_LINE_BEGIN
:
2219 case LFUN_CHAR_DELETE_FORWARD
:
2220 case LFUN_CHAR_DELETE_BACKWARD
:
2221 case LFUN_BREAK_PARAGRAPH
:
2222 case LFUN_PARAGRAPH_SPACING
:
2223 case LFUN_INSET_INSERT
:
2224 case LFUN_WORD_UPCASE
:
2225 case LFUN_WORD_LOWCASE
:
2226 case LFUN_WORD_CAPITALIZE
:
2227 case LFUN_CHARS_TRANSPOSE
:
2228 case LFUN_SERVER_GET_XY
:
2229 case LFUN_SERVER_SET_XY
:
2230 case LFUN_SERVER_GET_LAYOUT
:
2232 case LFUN_DATE_INSERT
:
2233 case LFUN_SELF_INSERT
:
2234 case LFUN_LINE_INSERT
:
2235 case LFUN_MATH_DISPLAY
:
2236 case LFUN_MATH_MODE
:
2237 case LFUN_MATH_MACRO
:
2238 case LFUN_MATH_MATRIX
:
2239 case LFUN_MATH_DELIM
:
2240 case LFUN_MATH_BIGDELIM
:
2241 case LFUN_MATH_INSERT
:
2242 case LFUN_MATH_SUBSCRIPT
:
2243 case LFUN_MATH_SUPERSCRIPT
:
2244 case LFUN_FONT_DEFAULT
:
2245 case LFUN_FONT_UNDERLINE
:
2246 case LFUN_FONT_SIZE
:
2248 case LFUN_TEXTSTYLE_APPLY
:
2249 case LFUN_TEXTSTYLE_UPDATE
:
2250 case LFUN_LAYOUT_PARAGRAPH
:
2251 case LFUN_PARAGRAPH_UPDATE
:
2252 case LFUN_ACCENT_UMLAUT
:
2253 case LFUN_ACCENT_CIRCUMFLEX
:
2254 case LFUN_ACCENT_GRAVE
:
2255 case LFUN_ACCENT_ACUTE
:
2256 case LFUN_ACCENT_TILDE
:
2257 case LFUN_ACCENT_CEDILLA
:
2258 case LFUN_ACCENT_MACRON
:
2259 case LFUN_ACCENT_DOT
:
2260 case LFUN_ACCENT_UNDERDOT
:
2261 case LFUN_ACCENT_UNDERBAR
:
2262 case LFUN_ACCENT_CARON
:
2263 case LFUN_ACCENT_BREVE
:
2264 case LFUN_ACCENT_TIE
:
2265 case LFUN_ACCENT_HUNGARIAN_UMLAUT
:
2266 case LFUN_ACCENT_CIRCLE
:
2267 case LFUN_ACCENT_OGONEK
:
2268 case LFUN_THESAURUS_ENTRY
:
2269 case LFUN_PARAGRAPH_PARAMS_APPLY
:
2270 case LFUN_PARAGRAPH_PARAMS
:
2272 case LFUN_BUFFER_END
:
2273 case LFUN_BUFFER_BEGIN
:
2274 case LFUN_BUFFER_BEGIN_SELECT
:
2275 case LFUN_BUFFER_END_SELECT
:
2276 case LFUN_UNICODE_INSERT
:
2277 // these are handled in our dispatch()
2286 && (cur
.empty() || !cur
.inset().insetAllowed(code
)))
2289 flag
.setEnabled(enable
);
2294 void Text::pasteString(Cursor
& cur
, docstring
const & clip
,
2297 cur
.clearSelection();
2298 if (!clip
.empty()) {
2301 insertStringAsParagraphs(cur
, clip
);
2303 insertStringAsLines(cur
, clip
);
2308 // FIXME: an item inset would make things much easier.
2309 bool Text::inDescriptionItem(Cursor
& cur
) const
2311 Paragraph
& par
= cur
.paragraph();
2312 pos_type
const pos
= cur
.pos();
2313 pos_type
const body_pos
= par
.beginOfBody();
2315 if (par
.layout().latextype
!= LATEX_LIST_ENVIRONMENT
2316 && (par
.layout().latextype
!= LATEX_ITEM_ENVIRONMENT
2317 || par
.layout().margintype
!= MARGIN_FIRST_DYNAMIC
))
2320 return (pos
< body_pos
2322 && (pos
== 0 || par
.getChar(pos
- 1) != ' ')));