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