]> git.lyx.org Git - lyx.git/blob - src/text3.C
1da785ddab2fd0c91ed8021966d1029e8db0df7c
[lyx.git] / src / text3.C
1 /* This file is part of
2  * ======================================================
3  *
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2002 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include "lyxtext.h"
14 #include "lyxrow.h"
15 #include "paragraph.h"
16 #include "BufferView.h"
17 #include "funcrequest.h"
18 #include "lyxrc.h"
19 #include "debug.h"
20 #include "bufferparams.h"
21 #include "buffer.h"
22 #include "ParagraphParameters.h"
23 #include "gettext.h"
24 #include "intl.h"
25 #include "support/lstrings.h"
26 #include "frontends/LyXView.h"
27 #include "frontends/screen.h"
28 #include "frontends/WorkArea.h"
29 #include "insets/insetspecialchar.h"
30 #include "insets/insettext.h"
31 #include "undo_funcs.h"
32
33 using std::endl;
34
35 extern string current_layout;
36
37
38 namespace {
39
40 void cursorPrevious(LyXText * text, BufferView * bv)
41 {
42         if (!text->cursor.row()->previous()) {
43                 if (text->first_y > 0) {
44                         int new_y = bv->text->first_y - bv->workarea().workHeight();
45                         bv->screen().draw(bv->text, bv, new_y < 0 ? 0 : new_y);
46                         bv->updateScrollbar();
47                 }
48                 return;
49         }
50
51         int y = text->first_y;
52         Row * cursorrow = text->cursor.row();
53
54         text->setCursorFromCoordinates(bv, text->cursor.x_fix(), y);
55         finishUndo();
56
57         int new_y;
58         if (cursorrow == bv->text->cursor.row()) {
59                 // we have a row which is higher than the workarea so we leave the
60                 // cursor on the start of the row and move only the draw up as soon
61                 // as we move the cursor or do something while inside the row (it may
62                 // span several workarea-heights) we'll move to the top again, but this
63                 // is better than just jump down and only display part of the row.
64                 new_y = bv->text->first_y - bv->workarea().workHeight();
65         } else {
66                 if (text->inset_owner) {
67                         new_y = bv->text->cursor.iy()
68                                 + bv->theLockingInset()->insetInInsetY() + y
69                                 + text->cursor.row()->height()
70                                 - bv->workarea().workHeight() + 1;
71                 } else {
72                         new_y = text->cursor.y()
73                                 - text->cursor.row()->baseline()
74                                 + text->cursor.row()->height()
75                                 - bv->workarea().workHeight() + 1;
76                 }
77         }
78         bv->screen().draw(bv->text, bv, new_y < 0 ? 0 : new_y);
79         if (text->cursor.row()->previous()) {
80                 LyXCursor cur;
81                 text->setCursor(bv, cur, text->cursor.row()->previous()->par(),
82                                                 text->cursor.row()->previous()->pos(), false);
83                 if (cur.y() > text->first_y) {
84                         text->cursorUp(bv, true);
85                 }
86         }
87         bv->updateScrollbar();
88 }
89
90
91 void cursorNext(LyXText * text, BufferView * bv)
92 {
93         if (!text->cursor.row()->next()) {
94                 int y = text->cursor.y() - text->cursor.row()->baseline() +
95                         text->cursor.row()->height();
96                 if (y > int(text->first_y + bv->workarea().workHeight())) {
97                         bv->screen().draw(bv->text, bv,
98                                                   bv->text->first_y + bv->workarea().workHeight());
99                         bv->updateScrollbar();
100                 }
101                 return;
102         }
103
104         int y = text->first_y + bv->workarea().workHeight();
105         if (text->inset_owner && !text->first_y) {
106                 y -= (bv->text->cursor.iy()
107                           - bv->text->first_y
108                           + bv->theLockingInset()->insetInInsetY());
109         }
110
111         text->getRowNearY(y);
112
113         Row * cursorrow = text->cursor.row();
114         text->setCursorFromCoordinates(bv, text->cursor.x_fix(), y);
115         // + workarea().workHeight());
116         finishUndo();
117
118         int new_y;
119         if (cursorrow == bv->text->cursor.row()) {
120                 // we have a row which is higher than the workarea so we leave the
121                 // cursor on the start of the row and move only the draw down as soon
122                 // as we move the cursor or do something while inside the row (it may
123                 // span several workarea-heights) we'll move to the top again, but this
124                 // is better than just jump down and only display part of the row.
125                 new_y = bv->text->first_y + bv->workarea().workHeight();
126         } else {
127                 if (text->inset_owner) {
128                         new_y = bv->text->cursor.iy()
129                                 + bv->theLockingInset()->insetInInsetY()
130                                 + y - text->cursor.row()->baseline();
131                 } else {
132                         new_y =  text->cursor.y() - text->cursor.row()->baseline();
133                 }
134         }
135         bv->screen().draw(bv->text, bv, new_y);
136         if (text->cursor.row()->next()) {
137                 LyXCursor cur;
138                 text->setCursor(bv, cur, text->cursor.row()->next()->par(),
139                                                 text->cursor.row()->next()->pos(), false);
140                 if (cur.y() < int(text->first_y + bv->workarea().workHeight())) {
141                         text->cursorDown(bv, true);
142                 }
143         }
144         bv->updateScrollbar();
145 }
146
147 }
148
149
150 void LyXText::update(BufferView * bv, bool changed)
151 {
152         BufferView::UpdateCodes c = BufferView::SELECT | BufferView::FITCUR;
153         if (changed)
154                 bv->update(this, c | BufferView::CHANGE);
155         else
156                 bv->update(this, c);
157 }
158
159
160 void specialChar(LyXText * lt, BufferView * bv, InsetSpecialChar::Kind kind)
161 {
162         bv->hideCursor();
163         lt->update(bv);
164         InsetSpecialChar * new_inset = new InsetSpecialChar(kind);
165         if (!bv->insertInset(new_inset))
166                 delete new_inset;
167         else
168                 bv->updateInset(new_inset, true);
169 }
170
171
172 Inset::RESULT LyXText::dispatch(FuncRequest const & cmd)
173 {
174         BufferView * bv = cmd.view();
175
176         switch (cmd.action) {
177
178         case LFUN_APPENDIX: {
179                 Paragraph * par = cursor.par();
180                 bool start = !par->params().startOfAppendix();
181
182                 // ensure that we have only one start_of_appendix in this document
183                 Paragraph * tmp = ownerParagraph();
184                 for (; tmp; tmp = tmp->next())
185                         tmp->params().startOfAppendix(false);
186
187                 par->params().startOfAppendix(start);
188
189                 // we can set the refreshing parameters now
190                 status(cmd.view(), LyXText::NEED_MORE_REFRESH);
191                 refresh_y = 0;
192                 refresh_row = 0; // not needed for full update
193                 updateCounters(cmd.view());
194                 setCursor(cmd.view(), cursor.par(), cursor.pos());
195                 update(bv);
196                 break;
197         }
198
199         case LFUN_DELETE_WORD_FORWARD:
200                 bv->beforeChange(this);
201                 update(bv, false);
202                 deleteWordForward(bv);
203                 update(bv);
204                 bv->finishChange();
205                 break;
206
207         case LFUN_DELETE_WORD_BACKWARD:
208                 bv->beforeChange(this);
209                 update(bv, false);
210                 deleteWordBackward(bv);
211                 update(bv, true);
212                 bv->finishChange();
213                 break;
214
215         case LFUN_DELETE_LINE_FORWARD:
216                 bv->beforeChange(this);
217                 update(bv, false);
218                 deleteLineForward(bv);
219                 update(bv);
220                 bv->finishChange();
221                 break;
222
223         case LFUN_SHIFT_TAB:
224         case LFUN_TAB:
225                 if (!selection.mark())
226                         bv->beforeChange(this);
227                 update(bv, false);
228                 cursorTab(bv);
229                 bv->finishChange();
230                 break;
231
232         case LFUN_WORDRIGHT:
233                 if (!selection.mark())
234                         bv->beforeChange(this);
235                 update(bv, false);
236                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
237                         cursorLeftOneWord(bv);
238                 else
239                         cursorRightOneWord(bv);
240                 bv->finishChange();
241                 break;
242
243         case LFUN_WORDLEFT:
244                 if (!selection.mark())
245                         bv->beforeChange(this);
246                 update(bv, false);
247                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
248                         cursorRightOneWord(bv);
249                 else
250                         cursorLeftOneWord(bv);
251                 bv->finishChange();
252                 break;
253
254         case LFUN_BEGINNINGBUF:
255                 if (!selection.mark())
256                         bv->beforeChange(this);
257                 update(bv, false);
258                 cursorTop(bv);
259                 bv->finishChange();
260                 break;
261
262         case LFUN_ENDBUF:
263                 if (selection.mark())
264                         bv->beforeChange(this);
265                 update(bv, false);
266                 cursorBottom(bv);
267                 bv->finishChange();
268                 break;
269
270         case LFUN_RIGHTSEL:
271                 update(bv, false);
272                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
273                         cursorLeft(bv);
274                 else
275                         cursorRight(bv);
276                 bv->finishChange(true);
277                 break;
278
279         case LFUN_LEFTSEL:
280                 update(bv, false);
281                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
282                         cursorRight(bv);
283                 else
284                         cursorLeft(bv);
285                 bv->finishChange(true);
286                 break;
287
288         case LFUN_UPSEL:
289                 update(bv, false);
290                 cursorUp(bv, true);
291                 bv->finishChange(true);
292                 break;
293
294         case LFUN_DOWNSEL:
295                 update(bv, false);
296                 cursorDown(bv, true);
297                 bv->finishChange(true);
298                 break;
299
300         case LFUN_UP_PARAGRAPHSEL:
301                 update(bv, false);
302                 cursorUpParagraph(bv);
303                 bv->finishChange(true);
304                 break;
305
306         case LFUN_DOWN_PARAGRAPHSEL:
307                 update(bv, false);
308                 cursorDownParagraph(bv);
309                 bv->finishChange(true);
310                 break;
311
312         case LFUN_PRIORSEL:
313                 update(bv, false);
314                 cursorPrevious(this, bv);
315                 bv->finishChange(true);
316                 break;
317
318         case LFUN_NEXTSEL:
319                 update(bv, false);
320                 cursorNext(this, bv);
321                 bv->finishChange();
322                 break;
323
324         case LFUN_HOMESEL:
325                 update(bv, false);
326                 cursorHome(bv);
327                 bv->finishChange(true);
328                 break;
329
330         case LFUN_ENDSEL:
331                 update(bv, false);
332                 cursorEnd(bv);
333                 bv->finishChange(true);
334                 break;
335
336         case LFUN_WORDRIGHTSEL:
337                 update(bv, false);
338                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
339                         cursorLeftOneWord(bv);
340                 else
341                         cursorRightOneWord(bv);
342                 bv->finishChange(true);
343                 break;
344
345         case LFUN_WORDLEFTSEL:
346                 update(bv, false);
347                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
348                         cursorRightOneWord(bv);
349                 else
350                         cursorLeftOneWord(bv);
351                 bv->finishChange(true);
352                 break;
353
354         case LFUN_RIGHT: {
355                 bool is_rtl = cursor.par()->isRightToLeftPar(bv->buffer()->params);
356                 if (!selection.mark())
357                         bv->beforeChange(this);
358                 update(bv);
359                 if (is_rtl)
360                         cursorLeft(bv, false);
361                 if (cursor.pos() < cursor.par()->size()
362                     && cursor.par()->isInset(cursor.pos())
363                     && isHighlyEditableInset(cursor.par()->getInset(cursor.pos()))) {
364                         Inset * tmpinset = cursor.par()->getInset(cursor.pos());
365                         cmd.message(tmpinset->editMessage());
366                         tmpinset->edit(bv, !is_rtl);
367                         break;
368                 }
369                 if (!is_rtl)
370                         cursorRight(bv, false);
371                 bv->finishChange(false);
372                 break;
373         }
374
375         case LFUN_LEFT: {
376                 // This is soooo ugly. Isn`t it possible to make
377                 // it simpler? (Lgb)
378                 bool const is_rtl = cursor.par()->isRightToLeftPar(bv->buffer()->params);
379                 if (!selection.mark())
380                         bv->beforeChange(this);
381                 update(bv);
382                 LyXCursor const cur = cursor;
383                 if (!is_rtl)
384                         cursorLeft(bv, false);
385                 if ((is_rtl || cur != cursor) && // only if really moved!
386                     cursor.pos() < cursor.par()->size() &&
387                     cursor.par()->isInset(cursor.pos()) &&
388                     isHighlyEditableInset(cursor.par()->getInset(cursor.pos()))) {
389                         Inset * tmpinset = cursor.par()->getInset(cursor.pos());
390                         cmd.message(tmpinset->editMessage());
391                         tmpinset->edit(bv, is_rtl);
392                         break;
393                 }
394                 if (is_rtl)
395                         cursorRight(bv, false);
396                 bv->finishChange(false);
397                 break;
398         }
399
400         case LFUN_UP:
401                 if (!selection.mark())
402                         bv->beforeChange(this);
403                 bv->update(this, BufferView::UPDATE);
404                 cursorUp(bv);
405                 bv->finishChange(false);
406                 break;
407
408         case LFUN_DOWN:
409                 if (!selection.mark())
410                         bv->beforeChange(this);
411                 bv->update(this, BufferView::UPDATE);
412                 cursorDown(bv);
413                 bv->finishChange();
414                 break;
415
416         case LFUN_UP_PARAGRAPH:
417                 if (!selection.mark())
418                         bv->beforeChange(this);
419                 bv->update(this, BufferView::UPDATE);
420                 cursorUpParagraph(bv);
421                 bv->finishChange();
422                 break;
423
424         case LFUN_DOWN_PARAGRAPH:
425                 if (!selection.mark())
426                         bv->beforeChange(this);
427                 bv->update(this, BufferView::UPDATE);
428                 cursorDownParagraph(bv);
429                 bv->finishChange(false);
430                 break;
431
432         case LFUN_PRIOR:
433                 if (!selection.mark())
434                         bv->beforeChange(this);
435                 bv->update(this, BufferView::UPDATE);
436                 cursorPrevious(this, bv);
437                 bv->finishChange(false);
438                 // was:
439                 // finishUndo();
440                 // moveCursorUpdate(false, false);
441                 // owner_->view_state_changed();
442                 break;
443
444         case LFUN_NEXT:
445                 if (!selection.mark())
446                         bv->beforeChange(this);
447                 bv->update(this, BufferView::UPDATE);
448                 cursorNext(this, bv);
449                 bv->finishChange(false);
450                 break;
451
452         case LFUN_HOME:
453                 if (!selection.mark())
454                         bv->beforeChange(this);
455                 update(bv);
456                 cursorHome(bv);
457                 bv->finishChange(false);
458                 break;
459
460         case LFUN_END:
461                 if (!selection.mark())
462                         bv->beforeChange(this);
463                 update(bv);
464                 cursorEnd(bv);
465                 bv->finishChange(false);
466                 break;
467
468         case LFUN_BREAKLINE:
469                 bv->beforeChange(this);
470                 insertChar(bv, Paragraph::META_NEWLINE);
471                 update(bv, true);
472                 setCursor(bv, cursor.par(), cursor.pos());
473                 bv->moveCursorUpdate(false);
474                 break;
475
476         case LFUN_DELETE:
477                 if (!selection.set()) {
478                         Delete(bv);
479                         selection.cursor = cursor;
480                         update(bv);
481                         // It is possible to make it a lot faster still
482                         // just comment out the line below...
483                         bv->showCursor();
484                 } else {
485                         bv->cut(false);
486                 }
487                 bv->moveCursorUpdate(false);
488                 bv->owner()->view_state_changed();
489                 bv->switchKeyMap();
490                 break;
491
492         case LFUN_DELETE_SKIP:
493                 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
494                 if (!selection.set()) {
495                         LyXCursor cur = cursor;
496                         if (cur.pos() == cur.par()->size()) {
497                                 cursorRight(bv);
498                                 cur = cursor;
499                                 if (cur.pos() == 0
500                                     && !(cur.par()->params().spaceTop()
501                                          == VSpace (VSpace::NONE))) {
502                                         setParagraph(bv,
503                                                  cur.par()->params().lineTop(),
504                                                  cur.par()->params().lineBottom(),
505                                                  cur.par()->params().pagebreakTop(),
506                                                  cur.par()->params().pagebreakBottom(),
507                                                  VSpace(VSpace::NONE),
508                                                  cur.par()->params().spaceBottom(),
509                                                  cur.par()->params().spacing(),
510                                                  cur.par()->params().align(),
511                                                  cur.par()->params().labelWidthString(), 0);
512                                         cursorLeft(bv);
513                                         update(bv);
514                                 } else {
515                                         cursorLeft(bv);
516                                         Delete(bv);
517                                         selection.cursor = cursor;
518                                         update(bv);
519                                 }
520                         } else {
521                                 Delete(bv);
522                                 selection.cursor = cursor;
523                                 update(bv);
524                         }
525                 } else
526                         bv->cut(false);
527                 break;
528
529
530         case LFUN_BACKSPACE:
531                 if (!selection.set()) {
532                         if (bv->owner()->getIntl().getTransManager().backspace()) {
533                                 backspace(bv);
534                                 selection.cursor = cursor;
535                                 update(bv);
536                                 // It is possible to make it a lot faster still
537                                 // just comment out the line below...
538                                 bv->showCursor();
539                         }
540                 } else
541                         bv->cut(false);
542                 bv->owner()->view_state_changed();
543                 bv->switchKeyMap();
544                 break;
545
546         case LFUN_BACKSPACE_SKIP:
547                 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
548                 if (!selection.set()) {
549                         LyXCursor cur = cursor;
550                         if (cur.pos() == 0
551                             && !(cur.par()->params().spaceTop()
552                                  == VSpace (VSpace::NONE))) {
553                                 setParagraph(bv,
554                                          cur.par()->params().lineTop(),
555                                          cur.par()->params().lineBottom(),
556                                          cur.par()->params().pagebreakTop(),
557                                          cur.par()->params().pagebreakBottom(),
558                                          VSpace(VSpace::NONE), cur.par()->params().spaceBottom(),
559                                          cur.par()->params().spacing(),
560                                          cur.par()->params().align(),
561                                          cur.par()->params().labelWidthString(), 0);
562                                 update(bv);
563                         } else {
564                                 backspace(bv);
565                                 selection.cursor = cur;
566                                 update(bv);
567                         }
568                 } else
569                         bv->cut(false);
570                 break;
571
572         case LFUN_BREAKPARAGRAPH:
573                 bv->beforeChange(this);
574                 breakParagraph(bv, 0);
575                 update(bv);
576                 selection.cursor = cursor;
577                 bv->switchKeyMap();
578                 bv->owner()->view_state_changed();
579                 break;
580
581         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
582                 bv->beforeChange(this);
583                 breakParagraph(bv, 1);
584                 update(bv);
585                 selection.cursor = cursor;
586                 bv->switchKeyMap();
587                 bv->owner()->view_state_changed();
588                 break;
589
590         case LFUN_BREAKPARAGRAPH_SKIP: {
591                 // When at the beginning of a paragraph, remove
592                 // indentation and add a "defskip" at the top.
593                 // Otherwise, do the same as LFUN_BREAKPARAGRAPH.
594                 LyXCursor cur = cursor;
595                 bv->beforeChange(this);
596                 if (cur.pos() == 0) {
597                         if (cur.par()->params().spaceTop() == VSpace(VSpace::NONE)) {
598                                 setParagraph(bv,
599                                          cur.par()->params().lineTop(),
600                                          cur.par()->params().lineBottom(),
601                                          cur.par()->params().pagebreakTop(),
602                                          cur.par()->params().pagebreakBottom(),
603                                          VSpace(VSpace::DEFSKIP), cur.par()->params().spaceBottom(),
604                                          cur.par()->params().spacing(),
605                                          cur.par()->params().align(),
606                                          cur.par()->params().labelWidthString(), 1);
607                                 //update(bv);
608                         }
609                 }
610                 else {
611                         breakParagraph(bv, 0);
612                         //update(bv);
613                 }
614                 update(bv);
615                 selection.cursor = cur;
616                 bv->switchKeyMap();
617                 bv->owner()->view_state_changed();
618                 break;
619         }
620
621         case LFUN_PARAGRAPH_SPACING: {
622                 Paragraph * par = cursor.par();
623                 Spacing::Space cur_spacing = par->params().spacing().getSpace();
624                 float cur_value = 1.0;
625                 if (cur_spacing == Spacing::Other)
626                         cur_value = par->params().spacing().getValue();
627
628                 istringstream is(cmd.argument.c_str());
629                 string tmp;
630                 is >> tmp;
631                 Spacing::Space new_spacing = cur_spacing;
632                 float new_value = cur_value;
633                 if (tmp.empty()) {
634                         lyxerr << "Missing argument to `paragraph-spacing'"
635                                << endl;
636                 } else if (tmp == "single") {
637                         new_spacing = Spacing::Single;
638                 } else if (tmp == "onehalf") {
639                         new_spacing = Spacing::Onehalf;
640                 } else if (tmp == "double") {
641                         new_spacing = Spacing::Double;
642                 } else if (tmp == "other") {
643                         new_spacing = Spacing::Other;
644                         float tmpval = 0.0;
645                         is >> tmpval;
646                         lyxerr << "new_value = " << tmpval << endl;
647                         if (tmpval != 0.0)
648                                 new_value = tmpval;
649                 } else if (tmp == "default") {
650                         new_spacing = Spacing::Default;
651                 } else {
652                         lyxerr << _("Unknown spacing argument: ")
653                                << cmd.argument << endl;
654                 }
655                 if (cur_spacing != new_spacing || cur_value != new_value) {
656                         par->params().spacing(Spacing(new_spacing, new_value));
657                         redoParagraph(bv);
658                         update(bv);
659                 }
660                 break;
661         }
662
663         case LFUN_INSET_TOGGLE:
664                 bv->hideCursor();
665                 bv->beforeChange(this);
666                 update(bv, false);
667                 toggleInset(bv);
668                 update(bv, false);
669                 bv->switchKeyMap();
670                 break;
671
672         case LFUN_PROTECTEDSPACE:
673                 if (cursor.par()->layout()->free_spacing) {
674                         insertChar(bv, ' ');
675                         update(bv);
676                 } else {
677                         specialChar(this, bv, InsetSpecialChar::PROTECTED_SEPARATOR);
678                 }
679                 bv->moveCursorUpdate(false);
680                 break;
681
682         case LFUN_HYPHENATION:
683                 specialChar(this, bv, InsetSpecialChar::HYPHENATION);
684                 break;
685
686         case LFUN_LIGATURE_BREAK:
687                 specialChar(this, bv, InsetSpecialChar::LIGATURE_BREAK);
688                 break;
689
690         case LFUN_LDOTS:
691                 specialChar(this, bv, InsetSpecialChar::LDOTS);
692                 break;
693
694         case LFUN_HFILL:
695                 bv->hideCursor();
696                 update(bv, false);
697                 insertChar(bv, Paragraph::META_HFILL);
698                 update(bv);
699                 break;
700
701         case LFUN_END_OF_SENTENCE:
702                 specialChar(this, bv, InsetSpecialChar::END_OF_SENTENCE);
703                 break;
704
705         case LFUN_MENU_SEPARATOR:
706                 specialChar(this, bv, InsetSpecialChar::MENU_SEPARATOR);
707                 break;
708
709         case LFUN_MARK_OFF:
710                 bv->beforeChange(this);
711                 update(bv, false);
712                 selection.cursor = cursor;
713                 cmd.message(N_("Mark off"));
714                 break;
715
716         case LFUN_MARK_ON:
717                 bv->beforeChange(this);
718                 selection.mark(true);
719                 update(bv, false);
720                 selection.cursor = cursor;
721                 cmd.message(N_("Mark on"));
722                 break;
723
724         case LFUN_SETMARK:
725                 bv->beforeChange(this);
726                 if (selection.mark()) {
727                         update(bv);
728                         cmd.message(N_("Mark removed"));
729                 } else {
730                         selection.mark(true);
731                         update(bv);
732                         cmd.message(N_("Mark set"));
733                 }
734                 selection.cursor = cursor;
735                 break;
736
737         case LFUN_UPCASE_WORD:
738                 update(bv, false);
739                 changeCase(bv, LyXText::text_uppercase);
740                 if (inset_owner)
741                         bv->updateInset(inset_owner, true);
742                 update(bv);
743                 break;
744
745         case LFUN_LOWCASE_WORD:
746                 update(bv, false);
747                 changeCase(bv, LyXText::text_lowercase);
748                 if (inset_owner)
749                         bv->updateInset(inset_owner, true);
750                 update(bv);
751                 break;
752
753         case LFUN_CAPITALIZE_WORD:
754                 update(bv, false);
755                 changeCase(bv, LyXText::text_capitalization);
756                 if (inset_owner)
757                         bv->updateInset(inset_owner, true);
758                 update(bv);
759                 break;
760
761         case LFUN_TRANSPOSE_CHARS:
762                 update(bv, false);
763                 transposeChars(*bv);
764                 if (inset_owner)
765                         bv->updateInset(inset_owner, true);
766                 update(bv);
767                 break;
768
769         case LFUN_BEGINNINGBUFSEL:
770                 if (inset_owner)
771                         return Inset::UNDISPATCHED;
772                 update(bv, false);
773                 cursorTop(bv);
774                 bv->finishChange(true);
775                 break;
776
777         case LFUN_ENDBUFSEL:
778                 if (inset_owner)
779                         return Inset::UNDISPATCHED;
780                 update(bv, false);
781                 cursorBottom(bv);
782                 bv->finishChange(true);
783                 break;
784
785         case LFUN_GETXY:
786                 cmd.message(tostr(cursor.x()) + ' ' + tostr(cursor.y()));
787                 break;
788
789         case LFUN_SETXY: {
790                 int x = 0;
791                 int y = 0;
792                 istringstream is(cmd.argument.c_str());
793                 is >> x >> y;
794                 if (!is)
795                         lyxerr << "SETXY: Could not parse coordinates in '"
796                                << cmd.argument << std::endl;
797                 else 
798                         setCursorFromCoordinates(bv, x, y);
799                 break;
800         }
801
802         case LFUN_GETFONT:
803                 if (current_font.shape() == LyXFont::ITALIC_SHAPE)
804                         cmd.message("E");
805                 else if (current_font.shape() == LyXFont::SMALLCAPS_SHAPE)
806                         cmd.message("N");
807                 else
808                         cmd.message("0");
809                 break;
810
811         case LFUN_GETLAYOUT:
812                 cmd.message(tostr(cursor.par()->layout()));
813                 break;
814
815         case LFUN_LAYOUT: {
816                 lyxerr[Debug::INFO] << "LFUN_LAYOUT: (arg) "
817                   << cmd.argument << endl;
818
819                 // This is not the good solution to the empty argument
820                 // problem, but it will hopefully suffice for 1.2.0.
821                 // The correct solution would be to augument the
822                 // function list/array with information about what
823                 // functions needs arguments and their type.
824                 if (cmd.argument.empty()) {
825                         cmd.errorMessage(_("LyX function 'layout' needs an argument."));
826                         break;
827                 }
828
829                 // Derive layout number from given argument (string)
830                 // and current buffer's textclass (number)
831                 LyXTextClass const & tclass = bv->buffer()->params.getLyXTextClass();
832                 bool hasLayout = tclass.hasLayout(cmd.argument);
833                 string layout = cmd.argument;
834
835                 // If the entry is obsolete, use the new one instead.
836                 if (hasLayout) {
837                         string const & obs = tclass[layout]->obsoleted_by();
838                         if (!obs.empty())
839                                 layout = obs;
840                 }
841
842                 if (!hasLayout) {
843                         cmd.errorMessage(string(N_("Layout ")) + cmd.argument +
844                                 N_(" not known"));
845                         break;
846                 }
847
848                 bool change_layout = (current_layout != layout);
849                 if (!change_layout && selection.set() &&
850                         selection.start.par() != selection.end.par())
851                 {
852                         Paragraph * spar = selection.start.par();
853                         Paragraph * epar = selection.end.par()->next();
854                         while (spar != epar) {
855                                 if (spar->layout()->name() != current_layout) {
856                                         change_layout = true;
857                                         break;
858                                 }
859                         }
860                 }
861                 if (change_layout) {
862                         bv->hideCursor();
863                         current_layout = layout;
864                         update(bv, false);
865                         setLayout(bv, layout);
866                         bv->owner()->setLayout(layout);
867                         update(bv);
868                         bv->switchKeyMap();
869                 }
870                 break;
871         }
872
873         case LFUN_PASTESELECTION: {
874                 if (!bv->buffer())
875                         break;
876                 bv->hideCursor();
877                 // this was originally a beforeChange(bv->text), i.e
878                 // the outermost LyXText!
879                 bv->beforeChange(this);
880                 string const clip(bv->workarea().getClipboard());
881                 if (!clip.empty()) {
882                         if (cmd.argument == "paragraph")
883                                 insertStringAsParagraphs(bv, clip);
884                         else
885                                 insertStringAsLines(bv, clip);
886                         clearSelection();
887                         update(bv);
888                 }
889                 break;
890         }
891
892         case LFUN_SELFINSERT: {
893                 if (cmd.argument.empty())
894                         break;
895
896                 // Automatically delete the currently selected
897                 // text and replace it with what is being
898                 // typed in now. Depends on lyxrc settings
899                 // "auto_region_delete", which defaults to
900                 // true (on).
901
902                 if (lyxrc.auto_region_delete) {
903                         if (selection.set()) {
904                                 cutSelection(bv, false, false);
905                                 update(bv);
906                         }
907                         bv->workarea().haveSelection(false);
908                 }
909
910                 bv->beforeChange(this);
911                 LyXFont const old_font(real_current_font);
912
913                 string::const_iterator cit = cmd.argument.begin();
914                 string::const_iterator end = cmd.argument.end();
915                 for (; cit != end; ++cit)
916                         bv->owner()->getIntl().getTransManager().
917                                 TranslateAndInsert(*cit, this);
918
919                 update(bv);
920                 selection.cursor = cursor;
921                 bv->moveCursorUpdate(false);
922
923                 // real_current_font.number can change so we need to
924                 // update the minibuffer
925                 if (old_font != real_current_font)
926                         bv->owner()->view_state_changed();
927                 break;
928         }
929
930         default:
931                 return Inset::UNDISPATCHED;
932         }
933
934         return Inset::DISPATCHED;
935 }