]> git.lyx.org Git - lyx.git/blob - src/text3.C
move half of BufferView_pimpl::dispatch() to LyXText::dispatch()
[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/WorkArea.h"
28 #include "insets/insetspecialchar.h"
29 #include "insets/insettext.h"
30
31
32 void LyXText::update(BufferView * bv, bool changed)
33 {
34         BufferView::UpdateCodes c = BufferView::SELECT | BufferView::FITCUR;
35         if (changed)
36                 bv->update(this, c | BufferView::CHANGE);
37         else
38                 bv->update(this, c);
39 }
40
41
42 void specialChar(LyXText * lt, BufferView * bv, InsetSpecialChar::Kind kind)
43 {
44         bv->hideCursor();
45         lt->update(bv);
46         InsetSpecialChar * new_inset = new InsetSpecialChar(kind);
47         if (!bv->insertInset(new_inset))
48                 delete new_inset;
49         else
50                 bv->updateInset(new_inset, true);
51 }
52
53
54 Inset::RESULT LyXText::dispatch(FuncRequest const & cmd)
55 {
56         BufferView * bv = cmd.view();
57
58         switch (cmd.action) {
59
60         case LFUN_APPENDIX: {
61                 Paragraph * par = cursor.par();
62                 bool start = !par->params().startOfAppendix();
63
64                 // ensure that we have only one start_of_appendix in this document
65                 Paragraph * tmp = ownerParagraph();
66                 for (; tmp; tmp = tmp->next())
67                         tmp->params().startOfAppendix(false);
68
69                 par->params().startOfAppendix(start);
70
71                 // we can set the refreshing parameters now
72                 status(cmd.view(), LyXText::NEED_MORE_REFRESH);
73                 refresh_y = 0;
74                 refresh_row = 0; // not needed for full update
75                 updateCounters(cmd.view());
76                 setCursor(cmd.view(), cursor.par(), cursor.pos());
77                 update(bv);
78                 return Inset::DISPATCHED;
79         }
80
81         case LFUN_DELETE_WORD_FORWARD:
82                 bv->beforeChange(this);
83                 update(bv, false);
84                 deleteWordForward(bv);
85                 update(bv);
86                 bv->finishChange();
87                 return Inset::DISPATCHED;
88
89         case LFUN_DELETE_WORD_BACKWARD:
90                 bv->beforeChange(this);
91                 update(bv, false);
92                 deleteWordBackward(bv);
93                 update(bv, true);
94                 bv->finishChange();
95                 return Inset::DISPATCHED;
96
97         case LFUN_DELETE_LINE_FORWARD:
98                 bv->beforeChange(this);
99                 update(bv, false);
100                 deleteLineForward(bv);
101                 update(bv);
102                 bv->finishChange();
103                 return Inset::DISPATCHED;
104
105         case LFUN_SHIFT_TAB:
106         case LFUN_TAB:
107                 if (!selection.mark())
108                         bv->beforeChange(this);
109                 update(bv, false);
110                 cursorTab(bv);
111                 bv->finishChange();
112                 return Inset::DISPATCHED;
113
114         case LFUN_WORDRIGHT: 
115                 if (!selection.mark())
116                         bv->beforeChange(this);
117                 update(bv, false);
118                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
119                         cursorLeftOneWord(bv);
120                 else
121                         cursorRightOneWord(bv);
122                 bv->finishChange();
123                 return Inset::DISPATCHED;
124
125         case LFUN_WORDLEFT:
126                 if (!selection.mark())
127                         bv->beforeChange(this);
128                 update(bv, false);
129                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
130                         cursorRightOneWord(bv);
131                 else
132                         cursorLeftOneWord(bv);
133                 bv->finishChange();
134                 return Inset::DISPATCHED;
135
136         case LFUN_BEGINNINGBUF:
137                 if (!selection.mark())
138                         bv->beforeChange(this);
139                 update(bv, false);
140                 cursorTop(bv);
141                 bv->finishChange();
142                 return Inset::DISPATCHED;
143
144         case LFUN_ENDBUF:
145                 if (selection.mark())
146                         bv->beforeChange(this);
147                 update(bv, false);
148                 cursorBottom(bv);
149                 bv->finishChange();
150                 return Inset::DISPATCHED;
151
152         case LFUN_RIGHTSEL:
153                 update(bv, false);
154                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
155                         cursorLeft(bv);
156                 else
157                         cursorRight(bv);
158                 bv->finishChange(true);
159                 return Inset::DISPATCHED;
160
161         case LFUN_LEFTSEL:
162                 update(bv, false);
163                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
164                         cursorRight(bv);
165                 else
166                         cursorLeft(bv);
167                 bv->finishChange(true);
168                 return Inset::DISPATCHED;
169
170         case LFUN_UPSEL:
171                 update(bv, false);
172                 cursorUp(bv, true);
173                 bv->finishChange(true);
174                 return Inset::DISPATCHED;
175
176         case LFUN_DOWNSEL:
177                 update(bv, false);
178                 cursorDown(bv, true);
179                 bv->finishChange(true);
180                 return Inset::DISPATCHED;
181
182         case LFUN_UP_PARAGRAPHSEL:
183                 update(bv, false);
184                 cursorUpParagraph(bv);
185                 bv->finishChange(true);
186                 return Inset::DISPATCHED;
187
188         case LFUN_DOWN_PARAGRAPHSEL:
189                 update(bv, false);
190                 cursorDownParagraph(bv);
191                 bv->finishChange(true);
192                 return Inset::DISPATCHED;
193
194         case LFUN_PRIORSEL:
195                 update(bv, false);
196                 bv->cursorPrevious(this);
197                 bv->finishChange(true);
198                 return Inset::DISPATCHED;
199
200         case LFUN_NEXTSEL:
201                 update(bv, false);
202                 bv->cursorNext(this);
203                 bv->finishChange();
204                 return Inset::DISPATCHED;
205
206         case LFUN_HOMESEL:
207                 update(bv, false);
208                 cursorHome(bv);
209                 bv->finishChange(true);
210                 return Inset::DISPATCHED;
211
212         case LFUN_ENDSEL:
213                 update(bv, false);
214                 cursorEnd(bv);
215                 bv->finishChange(true);
216                 return Inset::DISPATCHED;
217
218         case LFUN_WORDRIGHTSEL:
219                 update(bv, false);
220                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
221                         cursorLeftOneWord(bv);
222                 else
223                         cursorRightOneWord(bv);
224                 bv->finishChange(true);
225                 return Inset::DISPATCHED;
226
227         case LFUN_WORDLEFTSEL:
228                 update(bv, false);
229                 if (cursor.par()->isRightToLeftPar(bv->buffer()->params))
230                         cursorRightOneWord(bv);
231                 else
232                         cursorLeftOneWord(bv);
233                 bv->finishChange(true);
234                 return Inset::DISPATCHED;
235
236         case LFUN_RIGHT: {
237                 bool is_rtl = cursor.par()->isRightToLeftPar(bv->buffer()->params);
238                 if (!selection.mark())
239                         bv->beforeChange(this);
240                 update(bv);
241                 if (is_rtl)
242                         cursorLeft(bv, false);
243                 if (cursor.pos() < cursor.par()->size()
244                     && cursor.par()->isInset(cursor.pos())
245                     && isHighlyEditableInset(cursor.par()->getInset(cursor.pos()))) {
246                         Inset * tmpinset = cursor.par()->getInset(cursor.pos());
247                         cmd.message(tmpinset->editMessage());
248                         if (is_rtl)
249                                 tmpinset->edit(bv, false);
250                         else
251                                 tmpinset->edit(bv);
252                         return Inset::DISPATCHED;
253                 }
254                 if (!is_rtl)
255                         cursorRight(bv, false);
256                 bv->finishChange(false);
257                 return Inset::DISPATCHED;
258         }
259
260         case LFUN_LEFT: {
261                 // This is soooo ugly. Isn`t it possible to make
262                 // it simpler? (Lgb)
263                 bool const is_rtl = cursor.par()->isRightToLeftPar(bv->buffer()->params);
264                 if (!selection.mark())
265                         bv->beforeChange(this);
266                 update(bv);
267                 LyXCursor const cur = cursor;
268                 if (!is_rtl)
269                         cursorLeft(bv, false);
270                 if ((is_rtl || cur != cursor) && // only if really moved!
271                     cursor.pos() < cursor.par()->size() &&
272                     cursor.par()->isInset(cursor.pos()) &&
273                     isHighlyEditableInset(cursor.par()->getInset(cursor.pos()))) {
274                         Inset * tmpinset = cursor.par()->getInset(cursor.pos());
275                         cmd.message(tmpinset->editMessage());
276                         if (is_rtl)
277                                 tmpinset->edit(bv);
278                         else
279                                 tmpinset->edit(bv, false);
280                         break;
281                         return Inset::DISPATCHED;
282                 }
283                 if (is_rtl)
284                         cursorRight(bv, false);
285                 bv->finishChange(false);
286                 return Inset::DISPATCHED;
287         }
288
289         case LFUN_UP:
290                 if (!selection.mark())
291                         bv->beforeChange(this);
292                 bv->update(this, BufferView::UPDATE);
293                 cursorUp(bv);
294                 bv->finishChange(false);
295                 return Inset::DISPATCHED;
296
297         case LFUN_DOWN:
298                 if (!selection.mark())
299                         bv->beforeChange(this);
300                 bv->update(this, BufferView::UPDATE);
301                 cursorDown(bv);
302                 bv->finishChange();
303                 return Inset::DISPATCHED;
304
305         case LFUN_UP_PARAGRAPH:
306                 if (!selection.mark())
307                         bv->beforeChange(this);
308                 bv->update(this, BufferView::UPDATE);
309                 cursorUpParagraph(bv);
310                 bv->finishChange();
311                 return Inset::DISPATCHED;
312
313         case LFUN_DOWN_PARAGRAPH:
314                 if (!selection.mark())
315                         bv->beforeChange(this);
316                 bv->update(this, BufferView::UPDATE);
317                 cursorDownParagraph(bv);
318                 bv->finishChange(false);
319                 return Inset::DISPATCHED;
320
321         case LFUN_PRIOR:
322                 if (!selection.mark())
323                         bv->beforeChange(this);
324                 bv->update(this, BufferView::UPDATE);
325                 bv->cursorPrevious(this);
326                 bv->finishChange(false);
327                 // was:
328                 // finishUndo();
329                 // moveCursorUpdate(false, false);
330                 // owner_->view_state_changed();
331                 return Inset::DISPATCHED;
332
333         case LFUN_NEXT:
334                 if (!selection.mark())
335                         bv->beforeChange(this);
336                 bv->update(this, BufferView::UPDATE);
337                 bv->cursorNext(this);
338                 bv->finishChange(false);
339                 return Inset::DISPATCHED;
340
341         case LFUN_HOME:
342                 if (!selection.mark())
343                         bv->beforeChange(this);
344                 update(bv);
345                 cursorHome(bv);
346                 bv->finishChange(false);
347                 return Inset::DISPATCHED;
348
349         case LFUN_END:
350                 if (!selection.mark())
351                         bv->beforeChange(this);
352                 update(bv);
353                 cursorEnd(bv);
354                 bv->finishChange(false);
355                 return Inset::DISPATCHED;
356
357         case LFUN_BREAKLINE:
358                 bv->beforeChange(this);
359                 insertChar(bv, Paragraph::META_NEWLINE);
360                 update(bv, true);
361                 setCursor(bv, cursor.par(), cursor.pos());
362                 bv->moveCursorUpdate(false);
363                 return Inset::DISPATCHED;
364
365         case LFUN_PROTECTEDSPACE:
366                 if (cursor.par()->layout()->free_spacing) {
367                         insertChar(bv, ' ');
368                         update(bv);
369                 } else {
370                         specialChar(this, bv, InsetSpecialChar::PROTECTED_SEPARATOR);
371                 }
372                 bv->moveCursorUpdate(false);
373                 return Inset::DISPATCHED;
374
375         case LFUN_HYPHENATION:
376                 specialChar(this, bv, InsetSpecialChar::HYPHENATION);
377                 return Inset::DISPATCHED;
378
379         case LFUN_LIGATURE_BREAK:
380                 specialChar(this, bv, InsetSpecialChar::LIGATURE_BREAK);
381                 return Inset::DISPATCHED;
382
383         case LFUN_LDOTS:
384                 specialChar(this, bv, InsetSpecialChar::LDOTS);
385                 return Inset::DISPATCHED;
386
387         case LFUN_HFILL:
388                 bv->hideCursor();
389                 update(bv, false);
390                 insertChar(bv, Paragraph::META_HFILL);
391                 update(bv);
392                 return Inset::DISPATCHED;
393
394         case LFUN_END_OF_SENTENCE:
395                 specialChar(this, bv, InsetSpecialChar::END_OF_SENTENCE);
396                 return Inset::DISPATCHED;
397
398         case LFUN_MENU_SEPARATOR:
399                 specialChar(this, bv, InsetSpecialChar::MENU_SEPARATOR);
400                 return Inset::DISPATCHED;
401
402         case LFUN_MARK_OFF:
403                 bv->beforeChange(this);
404                 update(bv, false);
405                 selection.cursor = cursor;
406                 cmd.message(N_("Mark off"));
407                 return Inset::DISPATCHED;
408
409         case LFUN_MARK_ON:
410                 bv->beforeChange(this);
411                 selection.mark(true);
412                 update(bv, false);
413                 selection.cursor = cursor;
414                 cmd.message(N_("Mark on"));
415                 return Inset::DISPATCHED;
416
417         case LFUN_SETMARK:
418                 bv->beforeChange(this);
419                 if (selection.mark()) {
420                         update(bv);
421                         cmd.message(N_("Mark removed"));
422                 } else {
423                         selection.mark(true);
424                         update(bv);
425                         cmd.message(N_("Mark set"));
426                 }
427                 selection.cursor = cursor;
428                 return Inset::DISPATCHED;
429
430         case LFUN_UPCASE_WORD:
431                 update(bv, false);
432                 changeCase(bv, LyXText::text_uppercase);
433                 if (inset_owner)
434                         bv->updateInset(inset_owner, true);
435                 update(bv);
436                 return Inset::DISPATCHED;
437
438         case LFUN_LOWCASE_WORD:
439                 update(bv, false);
440                 changeCase(bv, LyXText::text_lowercase);
441                 if (inset_owner)
442                         bv->updateInset(inset_owner, true);
443                 update(bv);
444                 return Inset::DISPATCHED;
445
446         case LFUN_CAPITALIZE_WORD:
447                 update(bv, false);
448                 changeCase(bv, LyXText::text_capitalization);
449                 if (inset_owner)
450                         bv->updateInset(inset_owner, true);
451                 update(bv);
452                 return Inset::DISPATCHED;
453
454         case LFUN_TRANSPOSE_CHARS:
455                 update(bv, false);
456                 transposeChars(*bv);
457                 if (inset_owner)
458                         bv->updateInset(inset_owner, true);
459                 update(bv);
460                 return Inset::DISPATCHED;
461
462         case LFUN_BEGINNINGBUFSEL:
463                 if (inset_owner)
464                         return Inset::UNDISPATCHED;
465                 update(bv, false);
466                 cursorTop(bv);
467                 bv->finishChange(true);
468                 return Inset::DISPATCHED;
469
470         case LFUN_ENDBUFSEL:
471                 if (inset_owner)
472                         return Inset::UNDISPATCHED;
473                 update(bv, false);
474                 cursorBottom(bv);
475                 bv->finishChange(true);
476                 return Inset::DISPATCHED;
477
478         case LFUN_GETXY:
479                 cmd.message(tostr(cursor.x()) + ' ' + tostr(cursor.y()));
480                 return Inset::DISPATCHED;
481
482         case LFUN_SETXY: {
483                 int x = 0;
484                 int y = 0;
485                 if (::sscanf(cmd.argument.c_str(), " %d %d", &x, &y) != 2)
486                         lyxerr << "SETXY: Could not parse coordinates in '"
487                                << cmd.argument << std::endl;
488                 setCursorFromCoordinates(bv, x, y);
489                 return Inset::DISPATCHED;
490         }
491
492         case LFUN_GETFONT:
493                 if (current_font.shape() == LyXFont::ITALIC_SHAPE)
494                         cmd.message("E");
495                 else if (current_font.shape() == LyXFont::SMALLCAPS_SHAPE)
496                         cmd.message("N");
497                 else
498                         cmd.message("0");
499                 return Inset::DISPATCHED;
500
501         case LFUN_GETLAYOUT:
502                 cmd.message(tostr(cursor.par()->layout()));
503                 return Inset::DISPATCHED;
504
505         case LFUN_SELFINSERT: {
506                 if (cmd.argument.empty())
507                         return Inset::DISPATCHED;
508
509                 // Automatically delete the currently selected
510                 // text and replace it with what is being
511                 // typed in now. Depends on lyxrc settings
512                 // "auto_region_delete", which defaults to
513                 // true (on).
514
515                 if (lyxrc.auto_region_delete) {
516                         if (selection.set()) {
517                                 cutSelection(bv, false, false);
518                                 update(bv);
519                         }
520                         bv->workarea().haveSelection(false);
521                 }
522
523                 bv->beforeChange(this);
524                 LyXFont const old_font(real_current_font);
525
526                 string::const_iterator cit = cmd.argument.begin();
527                 string::const_iterator end = cmd.argument.end();
528                 for (; cit != end; ++cit)
529                         bv->owner()->getIntl().getTransManager().
530                                 TranslateAndInsert(*cit, this);
531
532                 update(bv);
533                 selection.cursor = cursor;
534                 bv->moveCursorUpdate(false);
535
536                 // real_current_font.number can change so we need to
537                 // update the minibuffer
538                 if (old_font != real_current_font)
539                         bv->owner()->view_state_changed();
540                 return Inset::DISPATCHED;
541         }
542
543         default:
544                 return Inset::UNDISPATCHED;
545         }
546
547         // shut up compiler
548         return Inset::UNDISPATCHED;
549 }