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