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