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