]> git.lyx.org Git - lyx.git/blob - src/text3.C
This commit replaces BufferView->LyXView->Gui->[selection,clipboard] with theApp...
[lyx.git] / src / text3.C
1 /**
2  * \file text3.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup
7  * \author Lars Gullik Bjønnes
8  * \author Alfredo Braunstein
9  * \author Angus Leeming
10  * \author John Levon
11  * \author André Pönitz
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "lyxtext.h"
19
20 #include "BranchList.h"
21 #include "FloatList.h"
22 #include "FuncStatus.h"
23 #include "buffer.h"
24 #include "buffer_funcs.h"
25 #include "bufferparams.h"
26 #include "BufferView.h"
27 #include "cursor.h"
28 #include "coordcache.h"
29 #include "CutAndPaste.h"
30 #include "debug.h"
31 #include "dispatchresult.h"
32 #include "errorlist.h"
33 #include "factory.h"
34 #include "funcrequest.h"
35 #include "gettext.h"
36 #include "intl.h"
37 #include "language.h"
38 #include "LyXAction.h"
39 #include "lyxfunc.h"
40 #include "lyxlex.h"
41 #include "lyxrc.h"
42 #include "lyxrow.h"
43 #include "paragraph.h"
44 #include "paragraph_funcs.h"
45 #include "ParagraphParameters.h"
46 #include "undo.h"
47 #include "vspace.h"
48 #include "pariterator.h"
49
50 #include "frontends/Dialogs.h"
51 #include "frontends/LyXView.h"
52 #include "frontends/Clipboard.h"
53 #include "frontends/Selection.h"
54
55 #include "insets/insetcommand.h"
56 #include "insets/insetfloatlist.h"
57 #include "insets/insetnewline.h"
58 #include "insets/insetquotes.h"
59 #include "insets/insetspecialchar.h"
60 #include "insets/insettext.h"
61
62 #include "support/lstrings.h"
63 #include "support/lyxlib.h"
64 #include "support/convert.h"
65 #include "support/lyxtime.h"
66
67 #include "mathed/InsetMathHull.h"
68 #include "mathed/MathMacroTemplate.h"
69
70 #include <boost/current_function.hpp>
71
72 #include <clocale>
73 #include <sstream>
74
75 using lyx::char_type;
76 using lyx::docstring;
77 using lyx::pos_type;
78
79 using lyx::cap::copySelection;
80 using lyx::cap::cutSelection;
81 using lyx::cap::pasteSelection;
82 using lyx::cap::replaceSelection;
83
84 using lyx::support::isStrUnsignedInt;
85 using lyx::support::token;
86
87 using std::endl;
88 using std::string;
89 using std::istringstream;
90 using std::ostringstream;
91
92
93 extern string current_layout;
94
95
96 namespace {
97
98         // globals...
99         LyXFont freefont(LyXFont::ALL_IGNORE);
100         bool toggleall = false;
101
102
103         void toggleAndShow(LCursor & cur, LyXText * text,
104                 LyXFont const & font, bool toggleall = true)
105         {
106                 text->toggleFree(cur, font, toggleall);
107
108                 if (font.language() != ignore_language ||
109                                 font.number() != LyXFont::IGNORE) {
110                         Paragraph & par = cur.paragraph();
111                         text->bidi.computeTables(par, cur.buffer(), cur.textRow());
112                         if (cur.boundary() !=
113                                         text->bidi.isBoundary(cur.buffer(), par,
114                                                         cur.pos(),
115                                                         text->real_current_font))
116                                 text->setCursor(cur, cur.pit(), cur.pos(),
117                                                 false, !cur.boundary());
118                 }
119         }
120
121
122         void moveCursor(LCursor & cur, bool selecting)
123         {
124                 if (selecting || cur.mark())
125                         cur.setSelection();
126                 if (!cur.selection())
127                         theApp->selection().haveSelection(false);
128                 cur.bv().switchKeyMap();
129         }
130
131
132         void finishChange(LCursor & cur, bool selecting)
133         {
134                 finishUndo();
135                 moveCursor(cur, selecting);
136         }
137
138
139         void mathDispatch(LCursor & cur, FuncRequest const & cmd, bool display)
140         {
141                 recordUndo(cur);
142                 string sel = lyx::to_utf8(cur.selectionAsString(false));
143                 //lyxerr << "selection is: '" << sel << "'" << endl;
144
145                 // It may happen that sel is empty but there is a selection
146                 replaceSelection(cur);
147
148                 if (sel.empty()) {
149                         const int old_pos = cur.pos();
150                         cur.insert(new InsetMathHull(hullSimple));
151                         BOOST_ASSERT(old_pos == cur.pos());
152                         cur.nextInset()->edit(cur, true);
153                         // don't do that also for LFUN_MATH_MODE
154                         // unless you want end up with always changing
155                         // to mathrm when opening an inlined inset --
156                         // I really hate "LyXfunc overloading"...
157                         if (display)
158                                 cur.dispatch(FuncRequest(LFUN_MATH_DISPLAY));
159                         // Avoid an unnecessary undo step if cmd.argument
160                         // is empty
161                         if (!cmd.argument().empty())
162                                 cur.dispatch(FuncRequest(LFUN_MATH_INSERT,
163                                                          cmd.argument()));
164                 } else {
165                         // create a macro if we see "\\newcommand"
166                         // somewhere, and an ordinary formula
167                         // otherwise
168                         istringstream is(sel);
169                         if (sel.find("\\newcommand") == string::npos
170                             && sel.find("\\def") == string::npos)
171                         {
172                                 InsetMathHull * formula = new InsetMathHull;
173                                 LyXLex lex(0, 0);
174                                 lex.setStream(is);
175                                 formula->read(cur.buffer(), lex);
176                                 if (formula->getType() == hullNone)
177                                         // Don't create pseudo formulas if
178                                         // delimiters are left out
179                                         formula->mutate(hullSimple);
180                                 cur.insert(formula);
181                         } else
182                                 cur.insert(new MathMacroTemplate(is));
183                 }
184                 cur.message(lyx::from_utf8(N_("Math editor mode")));
185         }
186
187 } // namespace anon
188
189
190
191 namespace bv_funcs {
192
193 string const freefont2string()
194 {
195         string data;
196         if (font2string(freefont, toggleall, data))
197                 return data;
198         return string();
199 }
200
201 }
202
203 bool LyXText::cursorPrevious(LCursor & cur)
204 {
205         pos_type cpos = cur.pos();
206         lyx::pit_type cpar = cur.pit();
207
208         int x = cur.x_target();
209
210         bool updated = setCursorFromCoordinates(cur, x, 0);
211         if (updated)
212                 cur.bv().update();
213         updated |= cursorUp(cur);
214
215         if (cpar == cur.pit() && cpos == cur.pos()) {
216                 // we have a row which is taller than the workarea. The
217                 // simplest solution is to move to the previous row instead.
218                 updated |= cursorUp(cur);
219         }
220
221         finishUndo();
222         return updated;
223 }
224
225
226 bool LyXText::cursorNext(LCursor & cur)
227 {
228         pos_type cpos = cur.pos();
229         lyx::pit_type cpar = cur.pit();
230
231         int x = cur.x_target();
232         bool updated = setCursorFromCoordinates(cur, x, cur.bv().workHeight() - 1);
233         if (updated)
234                 cur.bv().update();
235         updated |= cursorDown(cur);
236
237         if (cpar == cur.pit() && cpos == cur.pos()) {
238                 // we have a row which is taller than the workarea. The
239                 // simplest solution is to move to the next row instead.
240                 updated |= cursorDown(cur);
241         }
242
243         finishUndo();
244         return updated;
245 }
246
247
248 namespace {
249
250 void specialChar(LCursor & cur, InsetSpecialChar::Kind kind)
251 {
252         lyx::cap::replaceSelection(cur);
253         cur.insert(new InsetSpecialChar(kind));
254         cur.posRight();
255 }
256
257
258 bool doInsertInset(LCursor & cur, LyXText * text,
259         FuncRequest const & cmd, bool edit, bool pastesel)
260 {
261         InsetBase * inset = createInset(&cur.bv(), cmd);
262         if (!inset)
263                 return false;
264
265         recordUndo(cur);
266         bool gotsel = false;
267         if (cur.selection()) {
268                 theApp->lyxFunc().dispatch(FuncRequest(LFUN_CUT));
269                 gotsel = true;
270         }
271         text->insertInset(cur, inset);
272
273         if (edit)
274                 inset->edit(cur, true);
275
276         if (gotsel && pastesel) {
277                 theApp->lyxFunc().dispatch(FuncRequest(LFUN_PASTE));
278                 // reset first par to default
279                 if (cur.lastpit() != 0 || cur.lastpos() != 0) {
280                         LyXLayout_ptr const layout =
281                                 cur.buffer().params().getLyXTextClass().defaultLayout();
282                         cur.text()->paragraphs().begin()->layout(layout);
283                 }
284         }
285         return true;
286 }
287
288
289 void update(LCursor & cur)
290 {
291         //we don't call update(true, false) directly to save a metrics call
292         if (cur.bv().fitCursor())
293                 cur.bv().update(Update::Force);
294 }
295
296
297 } // anon namespace
298
299
300 void LyXText::number(LCursor & cur)
301 {
302         LyXFont font(LyXFont::ALL_IGNORE);
303         font.setNumber(LyXFont::TOGGLE);
304         toggleAndShow(cur, this, font);
305 }
306
307
308 bool LyXText::isRTL(Paragraph const & par) const
309 {
310         return par.isRightToLeftPar(bv()->buffer()->params());
311 }
312
313
314 void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
315 {
316         lyxerr[Debug::ACTION] << "LyXText::dispatch: cmd: " << cmd << endl;
317
318         BOOST_ASSERT(cur.text() == this);
319         BufferView * bv = &cur.bv();
320         CursorSlice oldTopSlice = cur.top();
321         bool oldBoundary = cur.boundary();
322         bool sel = cur.selection();
323         // Signals that, even if needsUpdate == false, an update of the
324         // cursor paragraph is required
325         bool singleParUpdate = lyxaction.funcHasFlag(cmd.action,
326                 LyXAction::SingleParUpdate);
327         // Signals that a full-screen update is required
328         bool needsUpdate = !(lyxaction.funcHasFlag(cmd.action,
329                 LyXAction::NoUpdate) || singleParUpdate);
330         // Remember the old paragraph metric (_outer_ paragraph!)
331         Dimension olddim = cur.bottom().paragraph().dim();
332
333         switch (cmd.action) {
334
335         case LFUN_PARAGRAPH_MOVE_DOWN: {
336                 pit_type const pit = cur.pit();
337                 recUndo(pit, pit + 1);
338                 finishUndo();
339                 std::swap(pars_[pit], pars_[pit + 1]);
340
341                 ParIterator begin(cur);
342                 ++cur.pit();
343                 ParIterator end = boost::next(ParIterator(cur));
344                 updateLabels(cur.buffer(), begin, end);
345
346                 needsUpdate = true;
347                 break;
348         }
349
350         case LFUN_PARAGRAPH_MOVE_UP: {
351                 pit_type const pit = cur.pit();
352                 recUndo(pit - 1, pit);
353                 finishUndo();
354                 std::swap(pars_[pit], pars_[pit - 1]);
355
356                 ParIterator end = boost::next(ParIterator(cur));
357                 --cur.pit();
358                 ParIterator begin(cur);
359                 updateLabels(cur.buffer(), begin, end);
360
361                 needsUpdate = true;
362                 break;
363         }
364
365         case LFUN_APPENDIX: {
366                 Paragraph & par = cur.paragraph();
367                 bool start = !par.params().startOfAppendix();
368
369 #ifdef WITH_WARNINGS
370 #warning The code below only makes sense at top level.
371 // Should LFUN_APPENDIX be restricted to top-level paragraphs?
372 #endif
373                 // ensure that we have only one start_of_appendix in this document
374                 for (pit_type tmp = 0, end = pars_.size(); tmp != end; ++tmp) {
375                         if (pars_[tmp].params().startOfAppendix()) {
376                                 recUndo(tmp);
377                                 pars_[tmp].params().startOfAppendix(false);
378                                 break;
379                         }
380                 }
381
382                 recordUndo(cur);
383                 par.params().startOfAppendix(start);
384
385                 // we can set the refreshing parameters now
386                 updateLabels(cur.buffer());
387                 break;
388         }
389
390         case LFUN_WORD_DELETE_FORWARD:
391                 cur.clearSelection();
392                 deleteWordForward(cur);
393                 finishChange(cur, false);
394                 break;
395
396         case LFUN_WORD_DELETE_BACKWARD:
397                 cur.clearSelection();
398                 deleteWordBackward(cur);
399                 finishChange(cur, false);
400                 break;
401
402         case LFUN_LINE_DELETE:
403                 cur.clearSelection();
404                 deleteLineForward(cur);
405                 finishChange(cur, false);
406                 break;
407
408         case LFUN_BUFFER_BEGIN:
409         case LFUN_BUFFER_BEGIN_SELECT:
410                 cur.selHandle(cmd.action == LFUN_BUFFER_BEGIN_SELECT);
411                 if (cur.depth() == 1) {
412                         needsUpdate = cursorTop(cur);
413                 } else {
414                         cur.undispatched();
415                 }
416                 break;
417
418         case LFUN_BUFFER_END:
419         case LFUN_BUFFER_END_SELECT:
420                 cur.selHandle(cmd.action == LFUN_BUFFER_END_SELECT);
421                 if (cur.depth() == 1) {
422                         needsUpdate = cursorBottom(cur);
423                 } else {
424                         cur.undispatched();
425                 }
426                 break;
427
428         case LFUN_CHAR_FORWARD:
429         case LFUN_CHAR_FORWARD_SELECT:
430                 //lyxerr << BOOST_CURRENT_FUNCTION
431                 //       << " LFUN_CHAR_FORWARD[SEL]:\n" << cur << endl;
432                 cur.selHandle(cmd.action == LFUN_CHAR_FORWARD_SELECT);
433                 if (isRTL(cur.paragraph()))
434                         needsUpdate = cursorLeft(cur);
435                 else
436                         needsUpdate = cursorRight(cur);
437
438                 if (!needsUpdate && oldTopSlice == cur.top()
439                                 && cur.boundary() == oldBoundary) {
440                         cur.undispatched();
441                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
442                 }
443                 break;
444
445         case LFUN_CHAR_BACKWARD:
446         case LFUN_CHAR_BACKWARD_SELECT:
447                 //lyxerr << "handle LFUN_CHAR_BACKWARD[_SELECT]:\n" << cur << endl;
448                 cur.selHandle(cmd.action == LFUN_CHAR_BACKWARD_SELECT);
449                 if (isRTL(cur.paragraph()))
450                         needsUpdate = cursorRight(cur);
451                 else
452                         needsUpdate = cursorLeft(cur);
453
454                 if (!needsUpdate && oldTopSlice == cur.top()
455                         && cur.boundary() == oldBoundary) {
456                         cur.undispatched();
457                         cmd = FuncRequest(LFUN_FINISHED_LEFT);
458                 }
459                 break;
460
461         case LFUN_UP:
462         case LFUN_UP_SELECT:
463                 update(cur);
464                 //lyxerr << "handle LFUN_UP[SEL]:\n" << cur << endl;
465                 cur.selHandle(cmd.action == LFUN_UP_SELECT);
466
467                 needsUpdate = cursorUp(cur);
468                 if (!needsUpdate && oldTopSlice == cur.top()
469                           && cur.boundary() == oldBoundary) {
470                         cur.undispatched();
471                         cmd = FuncRequest(LFUN_FINISHED_UP);
472                 }
473                 break;
474
475         case LFUN_DOWN:
476         case LFUN_DOWN_SELECT:
477                 update(cur);
478                 //lyxerr << "handle LFUN_DOWN[SEL]:\n" << cur << endl;
479                 cur.selHandle(cmd.action == LFUN_DOWN_SELECT);
480                 needsUpdate = cursorDown(cur);
481                 if (!needsUpdate && oldTopSlice == cur.top() &&
482                     cur.boundary() == oldBoundary)
483                 {
484                         cur.undispatched();
485                         cmd = FuncRequest(LFUN_FINISHED_DOWN);
486                 }
487                 break;
488
489         case LFUN_PARAGRAPH_UP:
490         case LFUN_PARAGRAPH_UP_SELECT:
491                 cur.selHandle(cmd.action == LFUN_PARAGRAPH_UP_SELECT);
492                 needsUpdate = cursorUpParagraph(cur);
493                 break;
494
495         case LFUN_PARAGRAPH_DOWN:
496         case LFUN_PARAGRAPH_DOWN_SELECT:
497                 cur.selHandle(cmd.action == LFUN_PARAGRAPH_DOWN_SELECT);
498                 needsUpdate = cursorDownParagraph(cur);
499                 break;
500
501         case LFUN_SCREEN_UP:
502         case LFUN_SCREEN_UP_SELECT:
503                 update(cur);
504                 cur.selHandle(cmd.action == LFUN_SCREEN_UP_SELECT);
505                 if (cur.pit() == 0 && cur.textRow().pos() == 0) {
506                         cur.undispatched();
507                         cmd = FuncRequest(LFUN_FINISHED_UP);
508                 } else {
509                         needsUpdate = cursorPrevious(cur);
510                 }
511                 break;
512
513         case LFUN_SCREEN_DOWN:
514         case LFUN_SCREEN_DOWN_SELECT:
515                 update(cur);
516                 cur.selHandle(cmd.action == LFUN_SCREEN_DOWN_SELECT);
517                 if (cur.pit() == cur.lastpit()
518                           && cur.textRow().endpos() == cur.lastpos()) {
519                         cur.undispatched();
520                         cmd = FuncRequest(LFUN_FINISHED_DOWN);
521                 } else {
522                         needsUpdate = cursorNext(cur);
523                 }
524                 break;
525
526         case LFUN_LINE_BEGIN:
527         case LFUN_LINE_BEGIN_SELECT:
528                 update(cur);
529                 cur.selHandle(cmd.action == LFUN_LINE_BEGIN_SELECT);
530                 needsUpdate = cursorHome(cur);
531                 break;
532
533         case LFUN_LINE_END:
534         case LFUN_LINE_END_SELECT:
535                 update(cur);
536                 cur.selHandle(cmd.action == LFUN_LINE_END_SELECT);
537                 needsUpdate = cursorEnd(cur);
538                 break;
539
540         case LFUN_WORD_FORWARD:
541         case LFUN_WORD_FORWARD_SELECT:
542                 cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT);
543                 if (isRTL(cur.paragraph()))
544                         needsUpdate = cursorLeftOneWord(cur);
545                 else
546                         needsUpdate = cursorRightOneWord(cur);
547                 break;
548
549         case LFUN_WORD_BACKWARD:
550         case LFUN_WORD_BACKWARD_SELECT:
551                 cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT);
552                 if (isRTL(cur.paragraph()))
553                         needsUpdate = cursorRightOneWord(cur);
554                 else
555                         needsUpdate = cursorLeftOneWord(cur);
556                 break;
557
558         case LFUN_WORD_SELECT: {
559                 selectWord(cur, lyx::WHOLE_WORD);
560                 finishChange(cur, true);
561                 break;
562         }
563
564         case LFUN_BREAK_LINE: {
565                 // Not allowed by LaTeX (labels or empty par)
566                 if (cur.pos() > cur.paragraph().beginOfBody()) {
567                         lyx::cap::replaceSelection(cur);
568                         cur.insert(new InsetNewline);
569                         cur.posRight();
570                         moveCursor(cur, false);
571                 }
572                 break;
573         }
574
575         case LFUN_CHAR_DELETE_FORWARD:
576                 if (!cur.selection()) {
577                         if (cur.pos() == cur.paragraph().size())
578                                 // Par boundary, force full-screen update
579                                 singleParUpdate = false;
580                         needsUpdate = erase(cur);
581                         cur.resetAnchor();
582                         // It is possible to make it a lot faster still
583                         // just comment out the line below...
584                 } else {
585                         cutSelection(cur, true, false);
586                         singleParUpdate = false;
587                 }
588                 moveCursor(cur, false);
589                 break;
590
591         case LFUN_DELETE_FORWARD_SKIP:
592                 // Reverse the effect of LFUN_BREAK_PARAGRAPH_SKIP.
593                 if (!cur.selection()) {
594                         if (cur.pos() == cur.lastpos()) {
595                                 cursorRight(cur);
596                                 cursorLeft(cur);
597                         }
598                         erase(cur);
599                         cur.resetAnchor();
600                 } else {
601                         cutSelection(cur, true, false);
602                 }
603                 break;
604
605
606         case LFUN_CHAR_DELETE_BACKWARD:
607                 if (!cur.selection()) {
608                         if (bv->getIntl().getTransManager().backspace()) {
609                                 // Par boundary, full-screen update
610                                 if (cur.pos() == 0)
611                                         singleParUpdate = false;
612                                 needsUpdate = backspace(cur);
613                                 cur.resetAnchor();
614                                 // It is possible to make it a lot faster still
615                                 // just comment out the line below...
616                         }
617                 } else {
618                         cutSelection(cur, true, false);
619                         singleParUpdate = false;
620                 }
621                 bv->switchKeyMap();
622                 break;
623
624         case LFUN_DELETE_BACKWARD_SKIP:
625                 // Reverse the effect of LFUN_BREAK_PARAGRAPH_SKIP.
626                 if (!cur.selection()) {
627 #ifdef WITH_WARNINGS
628 #warning look here
629 #endif
630                         //CursorSlice cur = cursor();
631                         backspace(cur);
632                         //anchor() = cur;
633                 } else {
634                         cutSelection(cur, true, false);
635                 }
636                 break;
637
638         case LFUN_BREAK_PARAGRAPH:
639                 lyx::cap::replaceSelection(cur);
640                 breakParagraph(cur, 0);
641                 cur.resetAnchor();
642                 bv->switchKeyMap();
643                 break;
644
645         case LFUN_BREAK_PARAGRAPH_KEEP_LAYOUT:
646                 lyx::cap::replaceSelection(cur);
647                 breakParagraph(cur, 1);
648                 cur.resetAnchor();
649                 bv->switchKeyMap();
650                 break;
651
652         case LFUN_BREAK_PARAGRAPH_SKIP: {
653                 // When at the beginning of a paragraph, remove
654                 // indentation.  Otherwise, do the same as LFUN_BREAK_PARAGRAPH.
655                 lyx::cap::replaceSelection(cur);
656                 if (cur.pos() == 0)
657                         cur.paragraph().params().labelWidthString(string());
658                 else
659                         breakParagraph(cur, 0);
660                 cur.resetAnchor();
661                 bv->switchKeyMap();
662                 break;
663         }
664
665         case LFUN_PARAGRAPH_SPACING: {
666                 Paragraph & par = cur.paragraph();
667                 Spacing::Space cur_spacing = par.params().spacing().getSpace();
668                 string cur_value = "1.0";
669                 if (cur_spacing == Spacing::Other)
670                         cur_value = par.params().spacing().getValueAsString();
671
672                 istringstream is(lyx::to_utf8(cmd.argument()));
673                 string tmp;
674                 is >> tmp;
675                 Spacing::Space new_spacing = cur_spacing;
676                 string new_value = cur_value;
677                 if (tmp.empty()) {
678                         lyxerr << "Missing argument to `paragraph-spacing'"
679                                << endl;
680                 } else if (tmp == "single") {
681                         new_spacing = Spacing::Single;
682                 } else if (tmp == "onehalf") {
683                         new_spacing = Spacing::Onehalf;
684                 } else if (tmp == "double") {
685                         new_spacing = Spacing::Double;
686                 } else if (tmp == "other") {
687                         new_spacing = Spacing::Other;
688                         string tmpval = "0.0";
689                         is >> tmpval;
690                         lyxerr << "new_value = " << tmpval << endl;
691                         if (tmpval != "0.0")
692                                 new_value = tmpval;
693                 } else if (tmp == "default") {
694                         new_spacing = Spacing::Default;
695                 } else {
696                         lyxerr << lyx::to_utf8(_("Unknown spacing argument: "))
697                                << lyx::to_utf8(cmd.argument()) << endl;
698                 }
699                 if (cur_spacing != new_spacing || cur_value != new_value)
700                         par.params().spacing(Spacing(new_spacing, new_value));
701                 break;
702         }
703
704         case LFUN_INSET_INSERT: {
705                 recordUndo(cur);
706                 InsetBase * inset = createInset(bv, cmd);
707                 if (inset) {
708                         insertInset(cur, inset);
709                         cur.posRight();
710                 }
711                 break;
712         }
713
714         case LFUN_INSET_DISSOLVE:
715                 needsUpdate = dissolveInset(cur);
716                 break;
717
718         case LFUN_INSET_SETTINGS:
719                 cur.inset().showInsetDialog(bv);
720                 break;
721
722         case LFUN_SPACE_INSERT:
723                 if (cur.paragraph().layout()->free_spacing)
724                         insertChar(cur, ' ');
725                 else {
726                         doInsertInset(cur, this, cmd, false, false);
727                         cur.posRight();
728                 }
729                 moveCursor(cur, false);
730                 break;
731
732         case LFUN_HYPHENATION_POINT_INSERT:
733                 specialChar(cur, InsetSpecialChar::HYPHENATION);
734                 break;
735
736         case LFUN_LIGATURE_BREAK_INSERT:
737                 specialChar(cur, InsetSpecialChar::LIGATURE_BREAK);
738                 break;
739
740         case LFUN_DOTS_INSERT:
741                 specialChar(cur, InsetSpecialChar::LDOTS);
742                 break;
743
744         case LFUN_END_OF_SENTENCE_PERIOD_INSERT:
745                 specialChar(cur, InsetSpecialChar::END_OF_SENTENCE);
746                 break;
747
748         case LFUN_MENU_SEPARATOR_INSERT:
749                 specialChar(cur, InsetSpecialChar::MENU_SEPARATOR);
750                 break;
751
752         case LFUN_WORD_UPCASE:
753                 changeCase(cur, LyXText::text_uppercase);
754                 break;
755
756         case LFUN_WORD_LOWCASE:
757                 changeCase(cur, LyXText::text_lowercase);
758                 break;
759
760         case LFUN_WORD_CAPITALIZE:
761                 changeCase(cur, LyXText::text_capitalization);
762                 break;
763
764         case LFUN_CHARS_TRANSPOSE:
765                 recordUndo(cur);
766                 break;
767
768         case LFUN_PASTE:
769                 cur.message(_("Paste"));
770                 lyx::cap::replaceSelection(cur);
771                 if (isStrUnsignedInt(lyx::to_utf8(cmd.argument())))
772                         pasteSelection(cur, bv->buffer()->errorList("Paste"),
773                         convert<unsigned int>(lyx::to_utf8(cmd.argument())));
774                 else
775                         pasteSelection(cur, bv->buffer()->errorList("Paste"),
776                         0);
777                 bv->buffer()->errors("Paste");
778                 cur.clearSelection(); // bug 393
779                 bv->switchKeyMap();
780                 finishUndo();
781                 break;
782
783         case LFUN_CUT:
784                 cutSelection(cur, true, true);
785                 cur.message(_("Cut"));
786                 break;
787
788         case LFUN_COPY:
789                 copySelection(cur);
790                 cur.message(_("Copy"));
791                 break;
792
793         case LFUN_SERVER_GET_XY:
794                 cur.message(lyx::from_utf8(
795                         convert<string>(cursorX(cur.top(), cur.boundary())) + ' '
796                           + convert<string>(cursorY(cur.top(), cur.boundary()))));
797                 break;
798
799         case LFUN_SERVER_SET_XY: {
800                 int x = 0;
801                 int y = 0;
802                 istringstream is(lyx::to_utf8(cmd.argument()));
803                 is >> x >> y;
804                 if (!is)
805                         lyxerr << "SETXY: Could not parse coordinates in '"
806                                << lyx::to_utf8(cmd.argument()) << std::endl;
807                 else
808                         setCursorFromCoordinates(cur, x, y);
809                 break;
810         }
811
812         case LFUN_SERVER_GET_FONT:
813                 if (current_font.shape() == LyXFont::ITALIC_SHAPE)
814                         cur.message(lyx::from_utf8("E"));
815                 else if (current_font.shape() == LyXFont::SMALLCAPS_SHAPE)
816                         cur.message(lyx::from_utf8("N"));
817                 else
818                         cur.message(lyx::from_utf8("0"));
819                 break;
820
821         case LFUN_SERVER_GET_LAYOUT:
822                 cur.message(lyx::from_utf8(cur.paragraph().layout()->name()));
823                 break;
824
825         case LFUN_LAYOUT: {
826                 lyxerr[Debug::INFO] << "LFUN_LAYOUT: (arg) "
827                   << lyx::to_utf8(cmd.argument()) << endl;
828
829                 // This is not the good solution to the empty argument
830                 // problem, but it will hopefully suffice for 1.2.0.
831                 // The correct solution would be to augument the
832                 // function list/array with information about what
833                 // functions needs arguments and their type.
834                 if (cmd.argument().empty()) {
835                         cur.errorMessage(_("LyX function 'layout' needs an argument."));
836                         break;
837                 }
838
839                 // Derive layout number from given argument (string)
840                 // and current buffer's textclass (number)
841                 LyXTextClass const & tclass = bv->buffer()->params().getLyXTextClass();
842                 bool hasLayout = tclass.hasLayout(lyx::to_utf8(cmd.argument()));
843                 string layout = lyx::to_utf8(cmd.argument());
844
845                 // If the entry is obsolete, use the new one instead.
846                 if (hasLayout) {
847                         string const & obs = tclass[layout]->obsoleted_by();
848                         if (!obs.empty())
849                                 layout = obs;
850                 }
851
852                 if (!hasLayout) {
853                         cur.errorMessage(lyx::from_utf8(N_("Layout ")) + cmd.argument() +
854                                 lyx::from_utf8(N_(" not known")));
855                         break;
856                 }
857
858                 bool change_layout = (current_layout != layout);
859
860                 if (!change_layout && cur.selection() &&
861                         cur.selBegin().pit() != cur.selEnd().pit())
862                 {
863                         pit_type spit = cur.selBegin().pit();
864                         pit_type epit = cur.selEnd().pit() + 1;
865                         while (spit != epit) {
866                                 if (pars_[spit].layout()->name() != current_layout) {
867                                         change_layout = true;
868                                         break;
869                                 }
870                                 ++spit;
871                         }
872                 }
873
874                 if (change_layout) {
875                         current_layout = layout;
876                         setLayout(cur, layout);
877                         bv->owner()->setLayout(layout);
878                         bv->switchKeyMap();
879                 }
880                 break;
881         }
882
883         case LFUN_CLIPBOARD_PASTE: {
884                 cur.clearSelection();
885                 docstring const clip = theApp->clipboard().get();
886                 if (!clip.empty()) {
887                         recordUndo(cur);
888                         if (cmd.argument() == "paragraph")
889                                 insertStringAsParagraphs(cur, clip);
890                         else
891                                 insertStringAsLines(cur, clip);
892                 }
893                 break;
894         }
895
896         case LFUN_PRIMARY_SELECTION_PASTE: {
897                 cur.clearSelection();
898                 docstring const clip = theApp->selection().get();
899                 if (!clip.empty()) {
900                         recordUndo(cur);
901                         if (cmd.argument() == "paragraph")
902                                 insertStringAsParagraphs(cur, clip);
903                         else
904                                 insertStringAsLines(cur, clip);
905                 }
906                 break;
907         }
908
909         case LFUN_QUOTE_INSERT: {
910                 lyx::cap::replaceSelection(cur);
911                 Paragraph & par = cur.paragraph();
912                 lyx::pos_type pos = cur.pos();
913                 lyx::char_type c;
914                 if (pos == 0)
915                         c = ' ';
916                 else if (cur.prevInset() && cur.prevInset()->isSpace())
917                         c = ' ';
918                 else
919                         c = par.getChar(pos - 1);
920
921                 LyXLayout_ptr const & style = par.layout();
922
923                 BufferParams const & bufparams = bv->buffer()->params();
924                 if (!style->pass_thru
925                     && par.getFontSettings(bufparams, pos).language()->lang() != "hebrew") {
926                         string arg = lyx::to_utf8(cmd.argument());
927                         if (arg == "single")
928                                 cur.insert(new InsetQuotes(c,
929                                     bufparams.quotes_language,
930                                     InsetQuotes::SingleQ));
931                         else
932                                 cur.insert(new InsetQuotes(c,
933                                     bufparams.quotes_language,
934                                     InsetQuotes::DoubleQ));
935                         cur.posRight();
936                 }
937                 else
938                         theApp->lyxFunc().dispatch(FuncRequest(LFUN_SELF_INSERT, "\""));
939                 break;
940         }
941
942         case LFUN_DATE_INSERT:
943                 if (cmd.argument().empty())
944                         theApp->lyxFunc().dispatch(FuncRequest(LFUN_SELF_INSERT,
945                                 lyx::formatted_time(lyx::current_time())));
946                 else
947                         theApp->lyxFunc().dispatch(FuncRequest(LFUN_SELF_INSERT,
948                                 lyx::formatted_time(lyx::current_time(), lyx::to_utf8(cmd.argument()))));
949                 break;
950
951         case LFUN_MOUSE_TRIPLE:
952                 if (cmd.button() == mouse_button::button1) {
953                         cursorHome(cur);
954                         cur.resetAnchor();
955                         cursorEnd(cur);
956                         cur.setSelection();
957                         bv->cursor() = cur;
958                         theApp->selection().haveSelection(cur.selection());
959                 }
960                 break;
961
962         case LFUN_MOUSE_DOUBLE:
963                 if (cmd.button() == mouse_button::button1) {
964                         selectWord(cur, lyx::WHOLE_WORD_STRICT);
965                         bv->cursor() = cur;
966                         theApp->selection().haveSelection(cur.selection());
967                 }
968                 break;
969
970         // Single-click on work area
971         case LFUN_MOUSE_PRESS: {
972                 // Right click on a footnote flag opens float menu
973                 if (cmd.button() == mouse_button::button3)
974                         cur.clearSelection();
975
976                 // Middle button press pastes if we have a selection
977                 // We do this here as if the selection was inside an inset
978                 // it could get cleared on the unlocking of the inset so
979                 // we have to check this first
980                 bool paste_internally = false;
981                 if (cmd.button() == mouse_button::button2 && cur.selection()) {
982                         theApp->lyxFunc().dispatch(FuncRequest(LFUN_COPY));
983                         paste_internally = true;
984                 }
985
986                 bv->mouseSetCursor(cur);
987
988                 // Insert primary selection with middle mouse
989                 // if there is a local selection in the current buffer,
990                 // insert this
991                 if (cmd.button() == mouse_button::button2) {
992                         if (paste_internally)
993                                 theApp->lyxFunc().dispatch(FuncRequest(LFUN_PASTE));
994                         else
995                                 theApp->lyxFunc().dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph"));
996                 }
997
998                 break;
999         }
1000
1001         case LFUN_MOUSE_MOTION: {
1002                 // Only use motion with button 1
1003                 //if (cmd.button() != mouse_button::button1)
1004                 //      return false;
1005
1006                 // ignore motions deeper nested than the real anchor
1007                 LCursor & bvcur = cur.bv().cursor();
1008                 if (bvcur.anchor_.hasPart(cur)) {
1009                         CursorSlice old = bvcur.top();
1010
1011                         int const wh = bv->workHeight();
1012                         int const y = std::max(0, std::min(wh - 1, cmd.y));
1013
1014                         setCursorFromCoordinates(cur, cmd.x, y);
1015                         cur.x_target() = cmd.x;
1016                         if (cmd.y >= wh)
1017                                 cursorDown(cur);
1018                         else if (cmd.y < 0)
1019                                 cursorUp(cur);
1020                         // This is to allow jumping over large insets
1021                         if (cur.top() == old) {
1022                                 if (cmd.y >= wh)
1023                                         cursorDown(cur);
1024                                 else if (cmd.y < 0)
1025                                         cursorUp(cur);
1026                         }
1027
1028                         if (cur.top() == old)
1029                                 cur.noUpdate();
1030                         else {
1031                                 // don't set anchor_
1032                                 bvcur.setCursor(cur);
1033                                 bvcur.selection() = true;
1034                                 //lyxerr << "MOTION: " << bv->cursor() << endl;
1035                         }
1036
1037                 } else
1038                         cur.undispatched();
1039                 break;
1040         }
1041
1042         case LFUN_MOUSE_RELEASE: {
1043                 if (cmd.button() == mouse_button::button2)
1044                         break;
1045
1046                 // finish selection
1047                 if (cmd.button() == mouse_button::button1)
1048                         theApp->selection().haveSelection(cur.selection());
1049
1050                 bv->switchKeyMap();
1051                 bv->owner()->updateMenubar();
1052                 bv->owner()->updateToolbars();
1053                 break;
1054         }
1055
1056         case LFUN_SELF_INSERT: {
1057                 if (cmd.argument().empty())
1058                         break;
1059
1060                 // Automatically delete the currently selected
1061                 // text and replace it with what is being
1062                 // typed in now. Depends on lyxrc settings
1063                 // "auto_region_delete", which defaults to
1064                 // true (on).
1065
1066                 if (lyxrc.auto_region_delete) {
1067                         if (cur.selection())
1068                                 cutSelection(cur, false, false);
1069                         theApp->selection().haveSelection(false);
1070                 }
1071
1072                 cur.clearSelection();
1073                 LyXFont const old_font = real_current_font;
1074
1075                 docstring::const_iterator cit = cmd.argument().begin();
1076                 docstring::const_iterator end = cmd.argument().end();
1077                 for (; cit != end; ++cit)
1078 #if 0
1079                         bv->getIntl().getTransManager().
1080                                 translateAndInsert(*cit, this);
1081 #else
1082                         insertChar(bv->cursor(), *cit);
1083 #endif
1084
1085                 cur.resetAnchor();
1086                 moveCursor(cur, false);
1087                 break;
1088         }
1089
1090         case LFUN_URL_INSERT: {
1091                 InsetCommandParams p("url");
1092                 string const data = InsetCommandMailer::params2string("url", p);
1093                 bv->showInsetDialog("url", data, 0);
1094                 break;
1095         }
1096
1097         case LFUN_HTML_INSERT: {
1098                 InsetCommandParams p("htmlurl");
1099                 string const data = InsetCommandMailer::params2string("url", p);
1100                 bv->showInsetDialog("url", data, 0);
1101                 break;
1102         }
1103
1104         case LFUN_LABEL_INSERT: {
1105                 // Try to generate a valid label
1106                 string const contents = cmd.argument().empty() ?
1107                         cur.getPossibleLabel() : lyx::to_utf8(cmd.argument());
1108
1109                 InsetCommandParams p("label", contents);
1110                 string const data = InsetCommandMailer::params2string("label", p);
1111
1112                 if (cmd.argument().empty()) {
1113                         bv->showInsetDialog("label", data, 0);
1114                 } else {
1115                         FuncRequest fr(LFUN_INSET_INSERT, data);
1116                         dispatch(cur, fr);
1117                 }
1118                 break;
1119         }
1120
1121
1122 #if 0
1123         case LFUN_LIST_INSERT:
1124         case LFUN_THEOREM_INSERT:
1125         case LFUN_CAPTION_INSERT:
1126 #endif
1127         case LFUN_NOTE_INSERT:
1128         case LFUN_CHARSTYLE_INSERT:
1129         case LFUN_BOX_INSERT:
1130         case LFUN_BRANCH_INSERT:
1131         case LFUN_BIBITEM_INSERT:
1132         case LFUN_ERT_INSERT:
1133         case LFUN_FOOTNOTE_INSERT:
1134         case LFUN_MARGINALNOTE_INSERT:
1135         case LFUN_OPTIONAL_INSERT:
1136         case LFUN_ENVIRONMENT_INSERT:
1137                 // Open the inset, and move the current selection
1138                 // inside it.
1139                 doInsertInset(cur, this, cmd, true, true);
1140                 cur.posRight();
1141                 break;
1142
1143         case LFUN_TABULAR_INSERT:
1144                 // if there were no arguments, just open the dialog
1145                 if (doInsertInset(cur, this, cmd, false, true))
1146                         cur.posRight();
1147                 else
1148                         bv->showDialog("tabularcreate");
1149
1150                 break;
1151
1152         case LFUN_FLOAT_INSERT:
1153         case LFUN_FLOAT_WIDE_INSERT:
1154         case LFUN_WRAP_INSERT:
1155                 doInsertInset(cur, this, cmd, true, true);
1156                 cur.posRight();
1157                 // FIXME: the "Caption" name should not be hardcoded,
1158                 // but given by the float definition.
1159                 cur.dispatch(FuncRequest(LFUN_LAYOUT, "Caption"));
1160                 break;
1161
1162         case LFUN_INDEX_INSERT: {
1163                 InsetBase * inset = createInset(&cur.bv(), cmd);
1164                 if (!inset)
1165                         break;
1166
1167                 recordUndo(cur);
1168                 cur.clearSelection();
1169                 insertInset(cur, inset);
1170                 inset->edit(cur, true);
1171                 cur.posRight();
1172                 break;
1173         }
1174
1175         case LFUN_INDEX_PRINT:
1176         case LFUN_TOC_INSERT:
1177         case LFUN_HFILL_INSERT:
1178         case LFUN_LINE_INSERT:
1179         case LFUN_PAGEBREAK_INSERT:
1180                 // do nothing fancy
1181                 doInsertInset(cur, this, cmd, false, false);
1182                 cur.posRight();
1183                 break;
1184
1185         case LFUN_DEPTH_DECREMENT:
1186                 changeDepth(cur, DEC_DEPTH);
1187                 break;
1188
1189         case LFUN_DEPTH_INCREMENT:
1190                 changeDepth(cur, INC_DEPTH);
1191                 break;
1192
1193         case LFUN_MATH_DISPLAY:
1194                 mathDispatch(cur, cmd, true);
1195                 break;
1196
1197         case LFUN_MATH_IMPORT_SELECTION:
1198         case LFUN_MATH_MODE:
1199                 if (cmd.argument() == "on")
1200                         // don't pass "on" as argument
1201                         mathDispatch(cur, FuncRequest(LFUN_MATH_MODE), false);
1202                 else
1203                         mathDispatch(cur, cmd, false);
1204                 break;
1205
1206         case LFUN_MATH_MACRO:
1207                 if (cmd.argument().empty())
1208                         cur.errorMessage(lyx::from_utf8(N_("Missing argument")));
1209                 else {
1210                         string s = lyx::to_utf8(cmd.argument());
1211                         string const s1 = token(s, ' ', 1);
1212                         int const nargs = s1.empty() ? 0 : convert<int>(s1);
1213                         string const s2 = token(s, ' ', 2);
1214                         string const type = s2.empty() ? "newcommand" : s2;
1215                         cur.insert(new MathMacroTemplate(token(s, ' ', 0), nargs, type));
1216                         //cur.nextInset()->edit(cur, true);
1217                 }
1218                 break;
1219
1220         // passthrough hat and underscore outside mathed:
1221         case LFUN_MATH_SUBSCRIPT:
1222                 mathDispatch(cur, FuncRequest(LFUN_SELF_INSERT, "_"), false);
1223                 break;
1224         case LFUN_MATH_SUPERSCRIPT:
1225                 mathDispatch(cur, FuncRequest(LFUN_SELF_INSERT, "^"), false);
1226                 break;
1227
1228         case LFUN_MATH_INSERT:
1229         case LFUN_MATH_MATRIX:
1230         case LFUN_MATH_DELIM:
1231         case LFUN_MATH_BIGDELIM: {
1232                 cur.insert(new InsetMathHull(hullSimple));
1233                 cur.dispatch(FuncRequest(LFUN_CHAR_FORWARD));
1234                 cur.dispatch(cmd);
1235                 break;
1236         }
1237
1238         case LFUN_FONT_EMPH: {
1239                 LyXFont font(LyXFont::ALL_IGNORE);
1240                 font.setEmph(LyXFont::TOGGLE);
1241                 toggleAndShow(cur, this, font);
1242                 break;
1243         }
1244
1245         case LFUN_FONT_BOLD: {
1246                 LyXFont font(LyXFont::ALL_IGNORE);
1247                 font.setSeries(LyXFont::BOLD_SERIES);
1248                 toggleAndShow(cur, this, font);
1249                 break;
1250         }
1251
1252         case LFUN_FONT_NOUN: {
1253                 LyXFont font(LyXFont::ALL_IGNORE);
1254                 font.setNoun(LyXFont::TOGGLE);
1255                 toggleAndShow(cur, this, font);
1256                 break;
1257         }
1258
1259         case LFUN_FONT_CODE: {
1260                 LyXFont font(LyXFont::ALL_IGNORE);
1261                 font.setFamily(LyXFont::TYPEWRITER_FAMILY); // no good
1262                 toggleAndShow(cur, this, font);
1263                 break;
1264         }
1265
1266         case LFUN_FONT_SANS: {
1267                 LyXFont font(LyXFont::ALL_IGNORE);
1268                 font.setFamily(LyXFont::SANS_FAMILY);
1269                 toggleAndShow(cur, this, font);
1270                 break;
1271         }
1272
1273         case LFUN_FONT_ROMAN: {
1274                 LyXFont font(LyXFont::ALL_IGNORE);
1275                 font.setFamily(LyXFont::ROMAN_FAMILY);
1276                 toggleAndShow(cur, this, font);
1277                 break;
1278         }
1279
1280         case LFUN_FONT_DEFAULT: {
1281                 LyXFont font(LyXFont::ALL_INHERIT, ignore_language);
1282                 toggleAndShow(cur, this, font);
1283                 break;
1284         }
1285
1286         case LFUN_FONT_UNDERLINE: {
1287                 LyXFont font(LyXFont::ALL_IGNORE);
1288                 font.setUnderbar(LyXFont::TOGGLE);
1289                 toggleAndShow(cur, this, font);
1290                 break;
1291         }
1292
1293         case LFUN_FONT_SIZE: {
1294                 LyXFont font(LyXFont::ALL_IGNORE);
1295                 font.setLyXSize(lyx::to_utf8(cmd.argument()));
1296                 toggleAndShow(cur, this, font);
1297                 break;
1298         }
1299
1300         case LFUN_LANGUAGE: {
1301                 Language const * lang = languages.getLanguage(lyx::to_utf8(cmd.argument()));
1302                 if (!lang)
1303                         break;
1304                 LyXFont font(LyXFont::ALL_IGNORE);
1305                 font.setLanguage(lang);
1306                 toggleAndShow(cur, this, font);
1307                 bv->switchKeyMap();
1308                 break;
1309         }
1310
1311         case LFUN_FONT_FREE_APPLY:
1312                 toggleAndShow(cur, this, freefont, toggleall);
1313                 cur.message(_("Character set"));
1314                 break;
1315
1316         // Set the freefont using the contents of \param data dispatched from
1317         // the frontends and apply it at the current cursor location.
1318         case LFUN_FONT_FREE_UPDATE: {
1319                 LyXFont font;
1320                 bool toggle;
1321                 if (bv_funcs::string2font(lyx::to_utf8(cmd.argument()), font, toggle)) {
1322                         freefont = font;
1323                         toggleall = toggle;
1324                         toggleAndShow(cur, this, freefont, toggleall);
1325                         cur.message(_("Character set"));
1326                 }
1327                 break;
1328         }
1329
1330         case LFUN_FINISHED_LEFT:
1331                 lyxerr[Debug::DEBUG] << "handle LFUN_FINISHED_LEFT:\n" << cur << endl;
1332                 break;
1333
1334         case LFUN_FINISHED_RIGHT:
1335                 lyxerr[Debug::DEBUG] << "handle LFUN_FINISHED_RIGHT:\n" << cur << endl;
1336                 ++cur.pos();
1337                 break;
1338
1339         case LFUN_FINISHED_UP:
1340                 lyxerr[Debug::DEBUG] << "handle LFUN_FINISHED_UP:\n" << cur << endl;
1341                 cursorUp(cur);
1342                 break;
1343
1344         case LFUN_FINISHED_DOWN:
1345                 lyxerr[Debug::DEBUG] << "handle LFUN_FINISHED_DOWN:\n" << cur << endl;
1346                 cursorDown(cur);
1347                 break;
1348
1349         case LFUN_LAYOUT_PARAGRAPH: {
1350                 string data;
1351                 params2string(cur.paragraph(), data);
1352                 data = "show\n" + data;
1353                 bv->showDialogWithData("paragraph", data);
1354                 break;
1355         }
1356
1357         case LFUN_PARAGRAPH_UPDATE: {
1358                 string data;
1359                 params2string(cur.paragraph(), data);
1360
1361                 // Will the paragraph accept changes from the dialog?
1362                 bool const accept = !cur.inset().forceDefaultParagraphs(cur.idx());
1363
1364                 data = "update " + convert<string>(accept) + '\n' + data;
1365                 bv->updateDialog("paragraph", data);
1366                 break;
1367         }
1368
1369         case LFUN_ACCENT_UMLAUT:
1370         case LFUN_ACCENT_CIRCUMFLEX:
1371         case LFUN_ACCENT_GRAVE:
1372         case LFUN_ACCENT_ACUTE:
1373         case LFUN_ACCENT_TILDE:
1374         case LFUN_ACCENT_CEDILLA:
1375         case LFUN_ACCENT_MACRON:
1376         case LFUN_ACCENT_DOT:
1377         case LFUN_ACCENT_UNDERDOT:
1378         case LFUN_ACCENT_UNDERBAR:
1379         case LFUN_ACCENT_CARON:
1380         case LFUN_ACCENT_SPECIAL_CARON:
1381         case LFUN_ACCENT_BREVE:
1382         case LFUN_ACCENT_TIE:
1383         case LFUN_ACCENT_HUNGARIAN_UMLAUT:
1384         case LFUN_ACCENT_CIRCLE:
1385         case LFUN_ACCENT_OGONEK:
1386                 theApp->lyxFunc().handleKeyFunc(cmd.action);
1387                 if (!cmd.argument().empty())
1388                         // FIXME: Are all these characters encoded in one byte in utf8?
1389                         bv->getIntl().getTransManager()
1390                                 .translateAndInsert(cmd.argument()[0], this);
1391                 break;
1392
1393         case LFUN_FLOAT_LIST: {
1394                 LyXTextClass const & tclass = bv->buffer()->params().getLyXTextClass();
1395                 if (tclass.floats().typeExist(lyx::to_utf8(cmd.argument()))) {
1396                         // not quite sure if we want this...
1397                         recordUndo(cur);
1398                         cur.clearSelection();
1399                         breakParagraph(cur);
1400
1401                         if (cur.lastpos() != 0) {
1402                                 cursorLeft(cur);
1403                                 breakParagraph(cur);
1404                         }
1405
1406                         setLayout(cur, tclass.defaultLayoutName());
1407                         setParagraph(cur, Spacing(), LYX_ALIGN_LAYOUT, string(), 0);
1408                         insertInset(cur, new InsetFloatList(lyx::to_utf8(cmd.argument())));
1409                         cur.posRight();
1410                 } else {
1411                         lyxerr << "Non-existent float type: "
1412                                << lyx::to_utf8(cmd.argument()) << endl;
1413                 }
1414                 break;
1415         }
1416
1417         case LFUN_CHANGE_ACCEPT: {
1418                 acceptChange(cur);
1419                 break;
1420         }
1421
1422         case LFUN_CHANGE_REJECT: {
1423                 rejectChange(cur);
1424                 break;
1425         }
1426
1427         case LFUN_THESAURUS_ENTRY: {
1428                 docstring arg = cmd.argument();
1429                 if (arg.empty()) {
1430                         arg = cur.selectionAsString(false);
1431                         // FIXME
1432                         if (arg.size() > 100 || arg.empty()) {
1433                                 // Get word or selection
1434                                 selectWordWhenUnderCursor(cur, lyx::WHOLE_WORD);
1435                                 arg = cur.selectionAsString(false);
1436                         }
1437                 }
1438                 bv->showDialogWithData("thesaurus", lyx::to_utf8(arg));
1439                 break;
1440         }
1441
1442         case LFUN_PARAGRAPH_PARAMS_APPLY: {
1443                 // Given data, an encoding of the ParagraphParameters
1444                 // generated in the Paragraph dialog, this function sets
1445                 // the current paragraph appropriately.
1446                 istringstream is(lyx::to_utf8(cmd.argument()));
1447                 LyXLex lex(0, 0);
1448                 lex.setStream(is);
1449                 ParagraphParameters params;
1450                 params.read(lex);
1451                 setParagraph(cur,
1452                                          params.spacing(),
1453                                          params.align(),
1454                                          params.labelWidthString(),
1455                                          params.noindent());
1456                 cur.message(_("Paragraph layout set"));
1457                 break;
1458         }
1459
1460         case LFUN_ESCAPE:
1461                 if (cur.selection()) {
1462                         cur.selection() = false;
1463                 } else {
1464                         cur.undispatched();
1465                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
1466                 }
1467                 break;
1468
1469         default:
1470                 lyxerr[Debug::ACTION]
1471                         << BOOST_CURRENT_FUNCTION
1472                         << ": Command " << cmd
1473                         << " not DISPATCHED by LyXText" << endl;
1474                 cur.undispatched();
1475                 break;
1476         }
1477
1478         if (singleParUpdate)
1479                 // Inserting characters does not change par height
1480                 if (cur.bottom().paragraph().dim().height()
1481                     == olddim.height()) {
1482                         // if so, update _only_ this paragraph
1483                         cur.bv().update(Update::SinglePar |
1484                                         Update::FitCursor |
1485                                         Update::MultiParSel);
1486                         cur.noUpdate();
1487                         return;
1488                 } else
1489                         needsUpdate = true;
1490         if (!needsUpdate
1491             && &oldTopSlice.inset() == &cur.inset()
1492             && oldTopSlice.idx() == cur.idx()
1493             && !sel
1494             && !cur.selection())
1495                 cur.noUpdate();
1496         else
1497                 cur.needsUpdate();
1498 }
1499
1500
1501 bool LyXText::getStatus(LCursor & cur, FuncRequest const & cmd,
1502                         FuncStatus & flag) const
1503 {
1504         BOOST_ASSERT(cur.text() == this);
1505
1506         LyXFont const & font = real_current_font;
1507         bool enable = true;
1508         InsetBase::Code code = InsetBase::NO_CODE;
1509
1510         switch (cmd.action) {
1511
1512         case LFUN_DEPTH_DECREMENT:
1513                 enable = changeDepthAllowed(cur, DEC_DEPTH);
1514                 break;
1515
1516         case LFUN_DEPTH_INCREMENT:
1517                 enable = changeDepthAllowed(cur, INC_DEPTH);
1518                 break;
1519
1520         case LFUN_APPENDIX:
1521                 flag.setOnOff(cur.paragraph().params().startOfAppendix());
1522                 return true;
1523
1524         case LFUN_BIBITEM_INSERT:
1525                 enable = (cur.paragraph().layout()->labeltype == LABEL_BIBLIO);
1526                 break;
1527
1528         case LFUN_DIALOG_SHOW_NEW_INSET:
1529                 if (cmd.argument() == "bibitem")
1530                         code = InsetBase::BIBITEM_CODE;
1531                 else if (cmd.argument() == "bibtex")
1532                         code = InsetBase::BIBTEX_CODE;
1533                 else if (cmd.argument() == "box")
1534                         code = InsetBase::BOX_CODE;
1535                 else if (cmd.argument() == "branch")
1536                         code = InsetBase::BRANCH_CODE;
1537                 else if (cmd.argument() == "citation")
1538                         code = InsetBase::CITE_CODE;
1539                 else if (cmd.argument() == "ert")
1540                         code = InsetBase::ERT_CODE;
1541                 else if (cmd.argument() == "external")
1542                         code = InsetBase::EXTERNAL_CODE;
1543                 else if (cmd.argument() == "float")
1544                         code = InsetBase::FLOAT_CODE;
1545                 else if (cmd.argument() == "graphics")
1546                         code = InsetBase::GRAPHICS_CODE;
1547                 else if (cmd.argument() == "include")
1548                         code = InsetBase::INCLUDE_CODE;
1549                 else if (cmd.argument() == "index")
1550                         code = InsetBase::INDEX_CODE;
1551                 else if (cmd.argument() == "label")
1552                         code = InsetBase::LABEL_CODE;
1553                 else if (cmd.argument() == "note")
1554                         code = InsetBase::NOTE_CODE;
1555                 else if (cmd.argument() == "ref")
1556                         code = InsetBase::REF_CODE;
1557                 else if (cmd.argument() == "toc")
1558                         code = InsetBase::TOC_CODE;
1559                 else if (cmd.argument() == "url")
1560                         code = InsetBase::URL_CODE;
1561                 else if (cmd.argument() == "vspace")
1562                         code = InsetBase::VSPACE_CODE;
1563                 else if (cmd.argument() == "wrap")
1564                         code = InsetBase::WRAP_CODE;
1565                 break;
1566
1567         case LFUN_ERT_INSERT:
1568                 code = InsetBase::ERT_CODE;
1569                 break;
1570         case LFUN_FOOTNOTE_INSERT:
1571                 code = InsetBase::FOOT_CODE;
1572                 break;
1573         case LFUN_TABULAR_INSERT:
1574                 code = InsetBase::TABULAR_CODE;
1575                 break;
1576         case LFUN_MARGINALNOTE_INSERT:
1577                 code = InsetBase::MARGIN_CODE;
1578                 break;
1579         case LFUN_FLOAT_INSERT:
1580         case LFUN_FLOAT_WIDE_INSERT:
1581                 code = InsetBase::FLOAT_CODE;
1582                 break;
1583         case LFUN_WRAP_INSERT:
1584                 code = InsetBase::WRAP_CODE;
1585                 break;
1586         case LFUN_FLOAT_LIST:
1587                 code = InsetBase::FLOAT_LIST_CODE;
1588                 break;
1589 #if 0
1590         case LFUN_LIST_INSERT:
1591                 code = InsetBase::LIST_CODE;
1592                 break;
1593         case LFUN_THEOREM_INSERT:
1594                 code = InsetBase::THEOREM_CODE;
1595                 break;
1596 #endif
1597         case LFUN_CAPTION_INSERT:
1598                 code = InsetBase::CAPTION_CODE;
1599                 break;
1600         case LFUN_NOTE_INSERT:
1601                 code = InsetBase::NOTE_CODE;
1602                 break;
1603         case LFUN_CHARSTYLE_INSERT:
1604                 code = InsetBase::CHARSTYLE_CODE;
1605                 if (cur.buffer().params().getLyXTextClass().charstyles().empty())
1606                         enable = false;
1607                 break;
1608         case LFUN_BOX_INSERT:
1609                 code = InsetBase::BOX_CODE;
1610                 break;
1611         case LFUN_BRANCH_INSERT:
1612                 code = InsetBase::BRANCH_CODE;
1613                 if (cur.buffer().getMasterBuffer()->params().branchlist().empty())
1614                         enable = false;
1615                 break;
1616         case LFUN_LABEL_INSERT:
1617                 code = InsetBase::LABEL_CODE;
1618                 break;
1619         case LFUN_OPTIONAL_INSERT:
1620                 code = InsetBase::OPTARG_CODE;
1621                 enable = numberOfOptArgs(cur.paragraph())
1622                         < cur.paragraph().layout()->optionalargs;
1623                 break;
1624         case LFUN_ENVIRONMENT_INSERT:
1625                 code = InsetBase::BOX_CODE;
1626                 break;
1627         case LFUN_INDEX_INSERT:
1628                 code = InsetBase::INDEX_CODE;
1629                 break;
1630         case LFUN_INDEX_PRINT:
1631                 code = InsetBase::INDEX_PRINT_CODE;
1632                 break;
1633         case LFUN_TOC_INSERT:
1634                 code = InsetBase::TOC_CODE;
1635                 break;
1636         case LFUN_HTML_INSERT:
1637         case LFUN_URL_INSERT:
1638                 code = InsetBase::URL_CODE;
1639                 break;
1640         case LFUN_QUOTE_INSERT:
1641                 // always allow this, since we will inset a raw quote
1642                 // if an inset is not allowed.
1643                 break;
1644         case LFUN_HYPHENATION_POINT_INSERT:
1645         case LFUN_LIGATURE_BREAK_INSERT:
1646         case LFUN_HFILL_INSERT:
1647         case LFUN_MENU_SEPARATOR_INSERT:
1648         case LFUN_DOTS_INSERT:
1649         case LFUN_END_OF_SENTENCE_PERIOD_INSERT:
1650                 code = InsetBase::SPECIALCHAR_CODE;
1651                 break;
1652         case LFUN_SPACE_INSERT:
1653                 // slight hack: we know this is allowed in math mode
1654                 if (cur.inTexted())
1655                         code = InsetBase::SPACE_CODE;
1656                 break;
1657
1658         case LFUN_INSET_MODIFY:
1659                 // We need to disable this, because we may get called for a
1660                 // tabular cell via
1661                 // InsetTabular::getStatus() -> InsetText::getStatus()
1662                 // and we don't handle LFUN_INSET_MODIFY.
1663                 enable = false;
1664                 break;
1665
1666         case LFUN_FONT_EMPH:
1667                 flag.setOnOff(font.emph() == LyXFont::ON);
1668                 return true;
1669
1670         case LFUN_FONT_NOUN:
1671                 flag.setOnOff(font.noun() == LyXFont::ON);
1672                 return true;
1673
1674         case LFUN_FONT_BOLD:
1675                 flag.setOnOff(font.series() == LyXFont::BOLD_SERIES);
1676                 return true;
1677
1678         case LFUN_FONT_SANS:
1679                 flag.setOnOff(font.family() == LyXFont::SANS_FAMILY);
1680                 return true;
1681
1682         case LFUN_FONT_ROMAN:
1683                 flag.setOnOff(font.family() == LyXFont::ROMAN_FAMILY);
1684                 return true;
1685
1686         case LFUN_FONT_CODE:
1687                 flag.setOnOff(font.family() == LyXFont::TYPEWRITER_FAMILY);
1688                 return true;
1689
1690         case LFUN_CUT:
1691         case LFUN_COPY:
1692                 enable = cur.selection();
1693                 break;
1694
1695         case LFUN_PASTE:
1696                 enable = lyx::cap::numberOfSelections() > 0;
1697                 break;
1698
1699         case LFUN_PARAGRAPH_MOVE_UP:
1700                 enable = cur.pit() > 0 && !cur.selection();
1701                 break;
1702
1703         case LFUN_PARAGRAPH_MOVE_DOWN:
1704                 enable = cur.pit() < cur.lastpit() && !cur.selection();
1705                 break;
1706
1707         case LFUN_INSET_DISSOLVE:
1708                 enable = !isMainText() && cur.inset().nargs() == 1;
1709                 break;
1710
1711         case LFUN_WORD_DELETE_FORWARD:
1712         case LFUN_WORD_DELETE_BACKWARD:
1713         case LFUN_LINE_DELETE:
1714         case LFUN_WORD_FORWARD:
1715         case LFUN_WORD_BACKWARD:
1716         case LFUN_CHAR_FORWARD:
1717         case LFUN_CHAR_FORWARD_SELECT:
1718         case LFUN_CHAR_BACKWARD:
1719         case LFUN_CHAR_BACKWARD_SELECT:
1720         case LFUN_UP:
1721         case LFUN_UP_SELECT:
1722         case LFUN_DOWN:
1723         case LFUN_DOWN_SELECT:
1724         case LFUN_PARAGRAPH_UP_SELECT:
1725         case LFUN_PARAGRAPH_DOWN_SELECT:
1726         case LFUN_SCREEN_UP_SELECT:
1727         case LFUN_SCREEN_DOWN_SELECT:
1728         case LFUN_LINE_BEGIN_SELECT:
1729         case LFUN_LINE_END_SELECT:
1730         case LFUN_WORD_FORWARD_SELECT:
1731         case LFUN_WORD_BACKWARD_SELECT:
1732         case LFUN_WORD_SELECT:
1733         case LFUN_PARAGRAPH_UP:
1734         case LFUN_PARAGRAPH_DOWN:
1735         case LFUN_SCREEN_UP:
1736         case LFUN_SCREEN_DOWN:
1737         case LFUN_LINE_BEGIN:
1738         case LFUN_LINE_END:
1739         case LFUN_BREAK_LINE:
1740         case LFUN_CHAR_DELETE_FORWARD:
1741         case LFUN_DELETE_FORWARD_SKIP:
1742         case LFUN_CHAR_DELETE_BACKWARD:
1743         case LFUN_DELETE_BACKWARD_SKIP:
1744         case LFUN_BREAK_PARAGRAPH:
1745         case LFUN_BREAK_PARAGRAPH_KEEP_LAYOUT:
1746         case LFUN_BREAK_PARAGRAPH_SKIP:
1747         case LFUN_PARAGRAPH_SPACING:
1748         case LFUN_INSET_INSERT:
1749         case LFUN_WORD_UPCASE:
1750         case LFUN_WORD_LOWCASE:
1751         case LFUN_WORD_CAPITALIZE:
1752         case LFUN_CHARS_TRANSPOSE:
1753         case LFUN_SERVER_GET_XY:
1754         case LFUN_SERVER_SET_XY:
1755         case LFUN_SERVER_GET_FONT:
1756         case LFUN_SERVER_GET_LAYOUT:
1757         case LFUN_LAYOUT:
1758         case LFUN_CLIPBOARD_PASTE:
1759         case LFUN_PRIMARY_SELECTION_PASTE:
1760         case LFUN_DATE_INSERT:
1761         case LFUN_SELF_INSERT:
1762         case LFUN_LINE_INSERT:
1763         case LFUN_PAGEBREAK_INSERT:
1764         case LFUN_MATH_DISPLAY:
1765         case LFUN_MATH_IMPORT_SELECTION:
1766         case LFUN_MATH_MODE:
1767         case LFUN_MATH_MACRO:
1768         case LFUN_MATH_INSERT:
1769         case LFUN_MATH_MATRIX:
1770         case LFUN_MATH_DELIM:
1771         case LFUN_MATH_BIGDELIM:
1772         case LFUN_MATH_SUBSCRIPT:
1773         case LFUN_MATH_SUPERSCRIPT:
1774         case LFUN_FONT_DEFAULT:
1775         case LFUN_FONT_UNDERLINE:
1776         case LFUN_FONT_SIZE:
1777         case LFUN_LANGUAGE:
1778         case LFUN_FONT_FREE_APPLY:
1779         case LFUN_FONT_FREE_UPDATE:
1780         case LFUN_LAYOUT_PARAGRAPH:
1781         case LFUN_PARAGRAPH_UPDATE:
1782         case LFUN_ACCENT_UMLAUT:
1783         case LFUN_ACCENT_CIRCUMFLEX:
1784         case LFUN_ACCENT_GRAVE:
1785         case LFUN_ACCENT_ACUTE:
1786         case LFUN_ACCENT_TILDE:
1787         case LFUN_ACCENT_CEDILLA:
1788         case LFUN_ACCENT_MACRON:
1789         case LFUN_ACCENT_DOT:
1790         case LFUN_ACCENT_UNDERDOT:
1791         case LFUN_ACCENT_UNDERBAR:
1792         case LFUN_ACCENT_CARON:
1793         case LFUN_ACCENT_SPECIAL_CARON:
1794         case LFUN_ACCENT_BREVE:
1795         case LFUN_ACCENT_TIE:
1796         case LFUN_ACCENT_HUNGARIAN_UMLAUT:
1797         case LFUN_ACCENT_CIRCLE:
1798         case LFUN_ACCENT_OGONEK:
1799         case LFUN_CHANGE_ACCEPT:
1800         case LFUN_CHANGE_REJECT:
1801         case LFUN_THESAURUS_ENTRY:
1802         case LFUN_PARAGRAPH_PARAMS_APPLY:
1803         case LFUN_ESCAPE:
1804         case LFUN_BUFFER_END:
1805         case LFUN_BUFFER_BEGIN:
1806         case LFUN_BUFFER_BEGIN_SELECT:
1807         case LFUN_BUFFER_END_SELECT:
1808                 // these are handled in our dispatch()
1809                 enable = true;
1810                 break;
1811
1812         default:
1813                 return false;
1814         }
1815
1816         if (code != InsetBase::NO_CODE
1817             && (cur.empty() || !cur.inset().insetAllowed(code)))
1818                 enable = false;
1819
1820         flag.enabled(enable);
1821         return true;
1822 }