]> git.lyx.org Git - lyx.git/blob - src/BufferView_pimpl.C
frontends fixes from Juergen S
[lyx.git] / src / BufferView_pimpl.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include "BufferView_pimpl.h"
8 #include "WorkArea.h"
9 #include "lyxscreen.h"
10 #include "lyxtext.h"
11 #include "lyxrow.h"
12 #include "paragraph.h"
13 #include "LyXView.h"
14 #include "commandtags.h"
15 #include "lyxfunc.h"
16 #include "debug.h"
17 #include "font.h"
18 #include "bufferview_funcs.h"
19 #include "TextCache.h"
20 #include "bufferlist.h"
21 #include "lyxrc.h"
22 #include "intl.h"
23 // added for Dispatch functions
24 #include "lyx_cb.h"
25 #include "lyx_main.h"
26 #include "FloatList.h"
27 #include "gettext.h"
28 #include "ParagraphParameters.h"
29 #include "undo_funcs.h"
30 #include "lyxtextclasslist.h"
31
32 #include "frontends/Dialogs.h"
33 #include "frontends/Alert.h"
34 #include "frontends/FileDialog.h"
35
36 #include "insets/insetbib.h"
37 #include "insets/insettext.h"
38 #include "insets/inseturl.h"
39 #include "insets/insetlatexaccent.h"
40 #include "insets/insettoc.h"
41 #include "insets/insetref.h"
42 #include "insets/insetparent.h"
43 #include "insets/insetindex.h"
44 #include "insets/insetnote.h"
45 #include "insets/insetinclude.h"
46 #include "insets/insetcite.h"
47 #include "insets/insetert.h"
48 #include "insets/insetexternal.h"
49 #include "insets/insetgraphics.h"
50 #include "insets/insetfoot.h"
51 #include "insets/insetmarginal.h"
52 #include "insets/insetminipage.h"
53 #include "insets/insetfloat.h"
54 #include "insets/insettabular.h"
55 #if 0
56 #include "insets/insettheorem.h"
57 #include "insets/insetlist.h"
58 #endif
59 #include "insets/insetcaption.h"
60 #include "insets/insetfloatlist.h"
61 #include "insets/insetspecialchar.h"
62
63 #include "mathed/formulabase.h"
64
65 #include "support/LAssert.h"
66 #include "support/lstrings.h"
67 #include "support/filetools.h"
68 #include "support/lyxfunctional.h"
69
70 #include <ctime>
71 #include <unistd.h>
72 #include <sys/wait.h>
73 #include <clocale>
74
75
76 extern string current_layout;
77
78 using std::vector;
79 using std::find_if;
80 using std::find;
81 using std::pair;
82 using std::endl;
83 using std::make_pair;
84 using std::min;
85 using SigC::slot;
86
87 using lyx::pos_type;
88 using lyx::textclass_type;
89
90 /* the selection possible is needed, that only motion events are 
91  * used, where the bottom press event was on the drawing area too */
92 bool selection_possible = false;
93
94 extern BufferList bufferlist;
95 extern char ascii_type;
96
97 extern int bibitemMaxWidth(BufferView *, LyXFont const &);
98
99
100 namespace {
101
102 const unsigned int saved_positions_num = 20;
103
104 inline
105 void waitForX()
106 {
107         XSync(fl_get_display(), 0);
108 }
109
110
111 void SetXtermCursor(Window win)
112 {
113         static Cursor cursor;
114         static bool cursor_undefined = true;
115         if (cursor_undefined) {
116                 cursor = XCreateFontCursor(fl_get_display(), XC_xterm);
117                 XFlush(fl_get_display());
118                 cursor_undefined = false;
119         }
120         XDefineCursor(fl_get_display(), win, cursor);
121         XFlush(fl_get_display());
122 }
123
124 } // anon namespace
125
126
127 BufferView::Pimpl::Pimpl(BufferView * b, LyXView * o,
128              int xpos, int ypos, int width, int height)
129         : bv_(b), owner_(o), buffer_(0),
130           current_scrollbar_value(0), cursor_timeout(400),
131           workarea_(xpos, ypos, width, height), using_xterm_cursor(false),
132           inset_slept(false)
133 {
134         // Setup the signals
135         workarea_.scrollCB.connect(slot(this, &BufferView::Pimpl::scrollCB));
136         workarea_.workAreaExpose
137                 .connect(slot(this, &BufferView::Pimpl::workAreaExpose));
138         workarea_.workAreaEnter
139                 .connect(slot(this, &BufferView::Pimpl::enterView));
140         workarea_.workAreaLeave
141                 .connect(slot(this, &BufferView::Pimpl::leaveView));
142         workarea_.workAreaButtonPress
143                 .connect(slot(this, &BufferView::Pimpl::workAreaButtonPress));
144         workarea_.workAreaButtonRelease
145                 .connect(slot(this,
146                               &BufferView::Pimpl::workAreaButtonRelease));
147         workarea_.workAreaMotionNotify
148                 .connect(slot(this, &BufferView::Pimpl::workAreaMotionNotify));
149         workarea_.workAreaDoubleClick
150                 .connect(slot(this, &BufferView::Pimpl::doubleClick));
151         workarea_.workAreaTripleClick
152                 .connect(slot(this, &BufferView::Pimpl::tripleClick));
153         workarea_.workAreaKeyPress
154                 .connect(slot(this, &BufferView::Pimpl::workAreaKeyPress));
155         workarea_.selectionRequested
156                 .connect(slot(this, &BufferView::Pimpl::selectionRequested)); 
157         workarea_.selectionLost
158                 .connect(slot(this, &BufferView::Pimpl::selectionLost));
159         
160         cursor_timeout.timeout.connect(slot(this,
161                                             &BufferView::Pimpl::cursorToggle));
162         cursor_timeout.start();
163         workarea_.setFocus();
164         saved_positions.resize(saved_positions_num);
165 }
166
167
168 Painter & BufferView::Pimpl::painter() 
169 {
170         return workarea_.getPainter();
171 }
172
173
174 void BufferView::Pimpl::buffer(Buffer * b)
175 {
176         lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
177                             << b << ")" << endl;
178         if (buffer_) {
179                 insetSleep();
180                 buffer_->delUser(bv_);
181
182                 // Put the old text into the TextCache, but
183                 // only if the buffer is still loaded.
184                 // Also set the owner of the test to 0
185                 //              bv_->text->owner(0);
186                 textcache.add(buffer_, workarea_.workWidth(), bv_->text);
187                 if (lyxerr.debugging())
188                         textcache.show(lyxerr, "BufferView::buffer");
189                 
190                 bv_->text = 0;
191         }
192
193         // Set current buffer
194         buffer_ = b;
195
196         if (bufferlist.getState() == BufferList::CLOSING) return;
197         
198         // Nuke old image
199         // screen is always deleted when the buffer is changed.
200         screen_.reset(0);
201
202         // If we are closing the buffer, use the first buffer as current
203         if (!buffer_) {
204                 buffer_ = bufferlist.first();
205         }
206
207         if (buffer_) {
208                 lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl;
209                 buffer_->addUser(bv_);
210                 // If we don't have a text object for this, we make one
211                 if (bv_->text == 0) {
212                         resizeCurrentBuffer();
213                 } else {
214                         updateScreen();
215                         updateScrollbar();
216                 }
217                 bv_->text->first_y = screen_->topCursorVisible(bv_->text);
218                 owner_->updateMenubar();
219                 owner_->updateToolbar();
220                 // Similarly, buffer-dependent dialogs should be updated or
221                 // hidden. This should go here because some dialogs (eg ToC)
222                 // require bv_->text.
223                 owner_->getDialogs()->updateBufferDependent(true);
224                 redraw();
225                 insetWakeup();
226         } else {
227                 lyxerr[Debug::INFO] << "  No Buffer!" << endl;
228                 owner_->updateMenubar();
229                 owner_->updateToolbar();
230                 owner_->getDialogs()->hideBufferDependent();
231                 updateScrollbar();
232                 workarea_.redraw();
233
234                 // Also remove all remaining text's from the testcache.
235                 // (there should not be any!) (if there is any it is a
236                 // bug!)
237                 if (lyxerr.debugging())
238                         textcache.show(lyxerr, "buffer delete all");
239                 textcache.clear();
240         }
241         // should update layoutchoice even if we don't have a buffer.
242         owner_->updateLayoutChoice();
243
244         owner_->updateWindowTitle();
245 }
246
247
248 void BufferView::Pimpl::resize(int xpos, int ypos, int width, int height)
249 {
250         workarea_.resize(xpos, ypos, width, height);
251         update(bv_->text, SELECT);
252         redraw();
253 }
254
255
256 void BufferView::Pimpl::resize()
257 {
258         if (buffer_)
259                 resizeCurrentBuffer();
260 }
261
262
263 void BufferView::Pimpl::redraw()
264 {
265         lyxerr[Debug::INFO] << "BufferView::redraw()" << endl;
266         workarea_.redraw();
267 }
268
269
270 bool BufferView::Pimpl::fitCursor()
271 {
272         lyx::Assert(screen_.get());
273
274         bool ret;
275
276         if (bv_->theLockingInset()) {
277                 bv_->theLockingInset()->fitInsetCursor(bv_);
278                 ret = true;
279         } else {
280                 ret = screen_->fitCursor(bv_->text, bv_);
281         }
282
283         bv_->owner()->getDialogs()->updateParagraph();
284         if (ret)
285             updateScrollbar();
286         return ret;
287 }
288
289
290 void BufferView::Pimpl::redoCurrentBuffer()
291 {
292         lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
293         if (buffer_ && bv_->text) {
294                 resize();
295                 owner_->updateLayoutChoice();
296         }
297 }
298
299
300 int BufferView::Pimpl::resizeCurrentBuffer()
301 {
302         lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
303         
304         Paragraph * par = 0;
305         Paragraph * selstartpar = 0;
306         Paragraph * selendpar = 0;
307         UpdatableInset * the_locking_inset = 0;
308         
309         pos_type pos = 0;
310         pos_type selstartpos = 0;
311         pos_type selendpos = 0;
312         bool selection = false;
313         bool mark_set  = false;
314
315         owner_->prohibitInput();
316
317         owner_->message(_("Formatting document..."));
318
319         if (bv_->text) {
320                 par = bv_->text->cursor.par();
321                 pos = bv_->text->cursor.pos();
322                 selstartpar = bv_->text->selection.start.par();
323                 selstartpos = bv_->text->selection.start.pos();
324                 selendpar = bv_->text->selection.end.par();
325                 selendpos = bv_->text->selection.end.pos();
326                 selection = bv_->text->selection.set();
327                 mark_set = bv_->text->selection.mark();
328                 the_locking_inset = bv_->theLockingInset();
329                 delete bv_->text;
330                 bv_->text = new LyXText(bv_);
331                 bv_->text->init(bv_);
332         } else {
333                 // See if we have a text in TextCache that fits
334                 // the new buffer_ with the correct width.
335                 bv_->text = textcache.findFit(buffer_, workarea_.workWidth());
336                 if (bv_->text) {
337                         if (lyxerr.debugging()) {
338                                 lyxerr << "Found a LyXText that fits:\n";
339                                 textcache.show(lyxerr, make_pair(buffer_, make_pair(workarea_.workWidth(), bv_->text)));
340                         }
341                         // Set the owner of the newly found text
342                         //      bv_->text->owner(bv_);
343                         if (lyxerr.debugging())
344                                 textcache.show(lyxerr, "resizeCurrentBuffer");
345                 } else {
346                         bv_->text = new LyXText(bv_);
347                         bv_->text->init(bv_);
348                 }
349         }
350         updateScreen();
351
352         if (par) {
353                 bv_->text->selection.set(true);
354                 /* at this point just to avoid the Delete-Empty-Paragraph
355                  * Mechanism when setting the cursor */
356                 bv_->text->selection.mark(mark_set);
357                 if (selection) {
358                         bv_->text->setCursor(bv_, selstartpar, selstartpos);
359                         bv_->text->selection.cursor = bv_->text->cursor;
360                         bv_->text->setCursor(bv_, selendpar, selendpos);
361                         bv_->text->setSelection(bv_);
362                         bv_->text->setCursor(bv_, par, pos);
363                 } else {
364                         bv_->text->setCursor(bv_, par, pos);
365                         bv_->text->selection.cursor = bv_->text->cursor;
366                         bv_->text->selection.set(false);
367                 }
368                 // remake the inset locking
369                 bv_->theLockingInset(the_locking_inset);
370         }
371         bv_->text->first_y = screen_->topCursorVisible(bv_->text);
372 #if 0
373         buffer_->resizeInsets(bv_);
374 #endif
375         // this will scroll the screen such that the cursor becomes visible
376         updateScrollbar();
377         redraw();
378
379         setState();
380         owner_->allowInput();
381
382         /// clear the "Formatting Document" message 
383         owner_->message("");
384
385         return 0;
386 }
387
388
389 void BufferView::Pimpl::updateScreen()
390 {
391         // Regenerate the screen.
392         screen_.reset(new LyXScreen(workarea_));
393 }
394
395
396 void BufferView::Pimpl::updateScrollbar()
397 {
398         /* If the text is smaller than the working area, the scrollbar
399          * maximum must be the working area height. No scrolling will 
400          * be possible */
401         if (!bv_->text) {
402                 workarea_.setScrollbar(0, 1.0);
403                 return;
404         }
405
406         long const text_height = bv_->text->height;
407         long const work_height = workarea_.height();
408
409         if (text_height <= work_height) {
410                 workarea_.setScrollbarBounds(0.0, 0.0);
411                 current_scrollbar_value = bv_->text->first_y;
412                 workarea_.setScrollbar(current_scrollbar_value, 1.0);
413                 return;
414         }
415         
416         double const lineh = bv_->text->defaultHeight();
417         double const slider_size =
418                 (text_height == 0) ? 1.0 : 1.0 / double(text_height);
419         
420         static long old_text_height;
421         static double old_lineh;
422         static double old_slider_size;
423
424         if (text_height != old_text_height) {
425                 workarea_.setScrollbarBounds(0.0,
426                                              text_height - work_height);
427                 old_text_height = text_height;
428         }
429         if (lineh != old_lineh) {
430                 workarea_.setScrollbarIncrements(lineh);
431                 old_lineh = lineh;
432         }
433         if (current_scrollbar_value != bv_->text->first_y
434             || slider_size != old_slider_size) {
435                 current_scrollbar_value = bv_->text->first_y;
436                 workarea_.setScrollbar(current_scrollbar_value, slider_size);
437                 old_slider_size = slider_size;
438         }
439 }
440
441
442 // Callback for scrollbar slider
443 void BufferView::Pimpl::scrollCB(double value)
444 {
445         if (!buffer_) return;
446
447         current_scrollbar_value = long(value);
448
449         if (current_scrollbar_value < 0)
450                 current_scrollbar_value = 0;
451    
452         if (!screen_.get())
453                 return;
454
455         screen_->draw(bv_->text, bv_, current_scrollbar_value);
456
457         if (!lyxrc.cursor_follows_scrollbar) {
458                 waitForX();
459                 return;
460         }
461  
462         LyXText * vbt = bv_->text;
463  
464         int const height = vbt->defaultHeight();
465         int const first = static_cast<int>((bv_->text->first_y + height));
466         int const last = static_cast<int>((bv_->text->first_y + workarea_.height() - height));
467
468         if (vbt->cursor.y() < first)
469                 vbt->setCursorFromCoordinates(bv_, 0, first);
470         else if (vbt->cursor.y() > last)
471                 vbt->setCursorFromCoordinates(bv_, 0, last);
472
473         waitForX();
474 }
475
476
477 int BufferView::Pimpl::scrollUp(long time)
478 {
479         if (!buffer_) return 0;
480         if (!screen_.get()) return 0;
481    
482         double value = workarea_.getScrollbarValue();
483    
484         if (value == 0) return 0;
485
486         float add_value =  (bv_->text->defaultHeight()
487                             + float(time) * float(time) * 0.125);
488    
489         if (add_value > workarea_.height())
490                 add_value = float(workarea_.height() -
491                                   bv_->text->defaultHeight());
492    
493         value -= add_value;
494
495         if (value < 0)
496                 value = 0;
497    
498         workarea_.setScrollbarValue(value);
499    
500         scrollCB(value); 
501         return 0;
502 }
503
504
505 int BufferView::Pimpl::scrollDown(long time)
506 {
507         if (!buffer_) return 0;
508         if (!screen_.get()) return 0;
509    
510         double value = workarea_.getScrollbarValue();
511         pair<float, float> p = workarea_.getScrollbarBounds();
512         double const max = p.second;
513         
514         if (value == max) return 0;
515
516         float add_value =  (bv_->text->defaultHeight()
517                             + float(time) * float(time) * 0.125);
518    
519         if (add_value > workarea_.height())
520                 add_value = float(workarea_.height() -
521                                   bv_->text->defaultHeight());
522    
523         value += add_value;
524    
525         if (value > max)
526                 value = max;
527
528         workarea_.setScrollbarValue(value);
529         
530         scrollCB(value); 
531         return 0;
532 }
533
534
535 void BufferView::Pimpl::workAreaKeyPress(KeySym keysym, unsigned int state)
536 {
537         bv_->owner()->getLyXFunc()->processKeySym(keysym, state);
538 }
539
540
541 void BufferView::Pimpl::workAreaMotionNotify(int x, int y, unsigned int state)
542 {
543         // Only use motion with button 1
544         if (!(state & Button1MotionMask))
545                 return;
546
547         if (!buffer_ || !screen_.get()) return;
548
549         // Check for inset locking
550         if (bv_->theLockingInset()) {
551                 LyXCursor cursor = bv_->text->cursor;
552                 LyXFont font = bv_->text->getFont(buffer_,
553                                                   cursor.par(), cursor.pos());
554                 int width = bv_->theLockingInset()->width(bv_, font);
555                 int inset_x = font.isVisibleRightToLeft()
556                         ? cursor.x() - width : cursor.x();
557                 int start_x = inset_x + bv_->theLockingInset()->scroll();
558                 bv_->theLockingInset()->
559                         insetMotionNotify(bv_,
560                                           x - start_x,
561                                           y - cursor.y() + bv_->text->first_y,
562                                           state);
563                 return;
564         }
565    
566         /* The test for not selection possible is needed, that only motion
567            events are used, where the bottom press event was on
568            the drawing area too */
569         if (!selection_possible)
570                 return;
571  
572         screen_->hideCursor();
573
574         bv_->text->setCursorFromCoordinates(bv_, x, y + bv_->text->first_y);
575       
576         if (!bv_->text->selection.set())
577                 update(bv_->text, BufferView::UPDATE); // Maybe an empty line was deleted
578       
579         bv_->text->setSelection(bv_);
580         screen_->toggleToggle(bv_->text, bv_);
581         fitCursor();
582         showCursor();
583 }
584
585
586 // Single-click on work area
587 void BufferView::Pimpl::workAreaButtonPress(int xpos, int ypos,
588                                             unsigned int button)
589 {
590         if (!buffer_ || !screen_.get()) return;
591
592         Inset * inset_hit = checkInsetHit(bv_->text, xpos, ypos);
593
594         // ok ok, this is a hack.
595         if (button == 4 || button == 5) {
596                 switch (button) {
597                 case 4:
598                         scrollUp(lyxrc.wheel_jump); // default 100, set in lyxrc
599                         break;
600                 case 5:
601                         scrollDown(lyxrc.wheel_jump);
602                         break;
603                 }
604         }
605         
606         if (bv_->theLockingInset()) {
607                 // We are in inset locking mode
608                 
609                 /* Check whether the inset was hit. If not reset mode,
610                    otherwise give the event to the inset */
611                 if (inset_hit == bv_->theLockingInset()) {
612                         bv_->theLockingInset()->
613                                 insetButtonPress(bv_,xpos, ypos,button);
614                         return;
615                 } else {
616                         bv_->unlockInset(bv_->theLockingInset());
617                 }
618         }
619         
620         if (!inset_hit)
621                 selection_possible = true;
622         screen_->hideCursor();
623
624         int const screen_first = bv_->text->first_y;
625         
626         // Middle button press pastes if we have a selection
627         bool paste_internally = false;
628         if (button == 2
629             && bv_->text->selection.set()) {
630                 owner_->getLyXFunc()->dispatch(LFUN_COPY);
631                 paste_internally = true;
632         }
633         
634         // Clear the selection
635         screen_->toggleSelection(bv_->text, bv_);
636         bv_->text->clearSelection();
637         bv_->text->fullRebreak(bv_);
638         update();
639         updateScrollbar();
640         
641         // Single left click in math inset?
642         if (isHighlyEditableInset(inset_hit)) {
643                 // Highly editable inset, like math
644                 UpdatableInset * inset = static_cast<UpdatableInset *>(inset_hit);
645                 selection_possible = false;
646                 owner_->updateLayoutChoice();
647                 owner_->message(inset->editMessage());
648                 // IMO the inset has to be first in edit-mode and then we send the
649                 // button press. (Jug 20020222)
650                 inset->edit(bv_); //, xpos, ypos, button);
651                 inset->insetButtonPress(bv_, xpos, ypos, button);
652                 return;
653         } 
654         
655         // Right click on a footnote flag opens float menu
656         if (button == 3) { 
657                 selection_possible = false;
658                 return;
659         }
660         
661         if (!inset_hit) // otherwise it was already set in checkInsetHit(...)
662                 bv_->text->setCursorFromCoordinates(bv_, xpos, ypos + screen_first);
663         finishUndo();
664         bv_->text->selection.cursor = bv_->text->cursor;
665         bv_->text->cursor.x_fix(bv_->text->cursor.x());
666         
667         owner_->updateLayoutChoice();
668         if (fitCursor()) {
669                 selection_possible = false;
670         }
671         
672         // Insert primary selection with middle mouse
673         // if there is a local selection in the current buffer,
674         // insert this
675         if (button == 2) {
676                 if (paste_internally)
677                         owner_->getLyXFunc()->dispatch(LFUN_PASTE);
678                 else
679                         owner_->getLyXFunc()->dispatch(LFUN_PASTESELECTION,
680                                                        "paragraph");
681                 selection_possible = false;
682                 return;
683         }
684 }
685
686
687 void BufferView::Pimpl::doubleClick(int /*x*/, int /*y*/, unsigned int button) 
688 {
689         // select a word
690         if (!buffer_)
691                 return;
692
693         LyXText * text = bv_->getLyXText();
694
695         if (text->bv_owner && bv_->theLockingInset())
696                 return;
697
698         if (screen_.get() && button == 1) {
699                 if (text->bv_owner) {
700                         screen_->hideCursor();
701                         screen_->toggleSelection(text, bv_);
702                         text->selectWord(bv_, LyXText::WHOLE_WORD_STRICT);
703                         screen_->toggleSelection(text, bv_, false);
704                 } else {
705                         text->selectWord(bv_, LyXText::WHOLE_WORD_STRICT);
706                 }
707                 /* This will fit the cursor on the screen
708                  * if necessary */
709                 update(text, BufferView::SELECT|BufferView::FITCUR);
710         }
711 }
712
713
714 void BufferView::Pimpl::tripleClick(int /*x*/, int /*y*/, unsigned int button)
715 {
716         // select a line
717         if (!buffer_)
718                 return;
719
720         LyXText * text = bv_->getLyXText();
721
722         if (text->bv_owner && bv_->theLockingInset())
723             return;
724
725         if (screen_.get() && (button == 1)) {
726                 if (text->bv_owner) {
727                         screen_->hideCursor();
728                         screen_->toggleSelection(text, bv_);
729                 }
730                 text->cursorHome(bv_);
731                 text->selection.cursor = text->cursor;
732                 text->cursorEnd(bv_);
733                 text->setSelection(bv_);
734                 if (text->bv_owner) {
735                         screen_->toggleSelection(text, bv_, false);
736                 }
737                 /* This will fit the cursor on the screen
738                  * if necessary */
739                 update(text, BufferView::SELECT|BufferView::FITCUR);
740         }
741 }
742
743
744 void BufferView::Pimpl::selectionRequested()
745 {
746         if (!available())
747                 return;
748  
749         string const sel(bv_->getLyXText()->selectionAsString(bv_->buffer(),
750                                                               false)); 
751         if (!sel.empty()) {
752                 workarea_.putClipboard(sel);
753         }
754 }
755
756  
757 void BufferView::Pimpl::selectionLost()
758 {
759         if (active() && available()) { 
760                 hideCursor();
761                 toggleSelection();
762                 bv_->getLyXText()->clearSelection();
763                 showCursor(); 
764         }
765 }
766
767  
768 void BufferView::Pimpl::enterView()
769 {
770         if (active() && available()) {
771                 SetXtermCursor(workarea_.getWin());
772                 using_xterm_cursor = true;
773         }
774 }
775
776
777 void BufferView::Pimpl::leaveView()
778 {
779         if (using_xterm_cursor) {
780                 XUndefineCursor(fl_get_display(), workarea_.getWin());
781                 using_xterm_cursor = false;
782         }
783 }
784
785
786 void BufferView::Pimpl::workAreaButtonRelease(int x, int y,
787                                               unsigned int button)
788 {
789         if (!buffer_ || !screen_.get()) return;
790
791         // If we hit an inset, we have the inset coordinates in these
792         // and inset_hit points to the inset.  If we do not hit an
793         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
794         Inset * inset_hit = checkInsetHit(bv_->text, x, y);
795
796         if (bv_->theLockingInset()) {
797                 // We are in inset locking mode.
798
799                 /* LyX does a kind of work-area grabbing for insets.
800                    Only a ButtonPress Event outside the inset will 
801                    force a insetUnlock. */
802                 bv_->theLockingInset()->
803                         insetButtonRelease(bv_, x, y, button);
804                 return;
805         }
806         
807         selection_possible = false;
808         
809         if (button == 2)
810                 return;
811
812         // finish selection
813         if (button == 1) {
814                 workarea_.haveSelection(bv_->getLyXText()->selection.set());
815         }
816  
817         setState();
818         owner_->showState();
819         owner_->updateMenubar();
820         owner_->updateToolbar();
821
822         // Did we hit an editable inset?
823         if (inset_hit) {
824                 selection_possible = false;
825
826                 // if we reach this point with a selection, it
827                 // must mean we are currently selecting.
828                 // But we don't want to open the inset
829                 // because that is annoying for the user. 
830                 // So just pretend we didn't hit it.
831                 // this is OK because a "kosher" ButtonRelease
832                 // will follow a ButtonPress that clears
833                 // the selection.
834                 // Note this also fixes selection drawing
835                 // problems if we end up opening an inset
836                 if (bv_->getLyXText()->selection.set())
837                         return;
838  
839                 // CHECK fix this proper in 0.13
840                 // well, maybe 13.0 !!!!!!!!!
841
842                 // Following a ref shouldn't issue
843                 // a push on the undo-stack
844                 // anylonger, now that we have
845                 // keybindings for following
846                 // references and returning from
847                 // references.  IMHO though, it
848                 // should be the inset's own business
849                 // to push or not push on the undo
850                 // stack. They don't *have* to
851                 // alter the document...
852                 // (Joacim)
853                 // ...or maybe the SetCursorParUndo()
854                 // below isn't necessary at all anylonger?
855                 if (inset_hit->lyxCode() == Inset::REF_CODE) {
856                         setCursorParUndo(bv_);
857                 }
858
859                 owner_->message(inset_hit->editMessage());
860
861                 if (isHighlyEditableInset(inset_hit)) {
862                         // Highly editable inset, like math
863                         UpdatableInset *inset = (UpdatableInset *)inset_hit;
864                         inset->insetButtonRelease(bv_, x, y, button);
865                 } else {
866                         inset_hit->insetButtonRelease(bv_, x, y, button);
867                         inset_hit->edit(bv_, x, y, button);
868                 }
869                 return;
870         }
871
872         // Maybe we want to edit a bibitem ale970302
873         if (bv_->text->cursor.par()->bibkey && x < 20 + 
874             bibitemMaxWidth(bv_, textclasslist[buffer_->params.textclass].defaultfont())) {
875                 bv_->text->cursor.par()->bibkey->edit(bv_, 0, 0, 0);
876         }
877
878         return;
879 }
880
881
882 Box BufferView::Pimpl::insetDimensions(LyXText const & text,
883                                        LyXCursor const & cursor) const
884 {
885         Paragraph /*const*/ & par = *cursor.par();
886         pos_type const pos = cursor.pos();
887
888         lyx::Assert(par.getInset(pos));
889  
890         Inset const & inset(*par.getInset(pos));
891
892         LyXFont const & font = text.getFont(buffer_, &par, pos);
893  
894         int const width = inset.width(bv_, font);
895         int const inset_x = font.isVisibleRightToLeft()
896                 ? (cursor.x() - width) : cursor.x();
897  
898         return Box(
899                 inset_x + inset.scroll(),
900                 inset_x + width,
901                 cursor.y() - inset.ascent(bv_, font),
902                 cursor.y() + inset.descent(bv_, font));
903 }
904  
905  
906 Inset * BufferView::Pimpl::checkInset(LyXText const & text,
907                                       LyXCursor const & cursor,
908                                       int & x, int & y) const
909 {
910         pos_type const pos(cursor.pos());
911         Paragraph /*const*/ & par(*cursor.par());
912
913         if (pos >= par.size() || !par.isInset(pos)) {
914                 return 0;
915         }
916
917         Inset /*const*/ * inset = par.getInset(pos);
918  
919         if (!isEditableInset(inset)) {
920                 return 0;
921         }
922
923         Box b(insetDimensions(text, cursor));
924
925         if (!b.contained(x, y)) {
926                 lyxerr[Debug::GUI] << "Missed inset at x,y " << x << "," << y 
927                         << " box " << b << endl;
928                 return 0;
929         }
930  
931         text.setCursor(bv_, &par, pos, true);
932  
933         x -= b.x1;
934         // The origin of an inset is on the baseline
935         y -= (text.cursor.y());
936   
937         return inset;
938 }
939
940  
941 Inset * BufferView::Pimpl::checkInsetHit(LyXText * text, int & x, int & y)
942 {
943         if (!screen_.get())
944                 return 0;
945   
946         int y_tmp = y + text->first_y;
947  
948         LyXCursor cursor;
949         text->setCursorFromCoordinates(bv_, cursor, x, y_tmp);
950  
951         Inset * inset(checkInset(*text, cursor, x, y_tmp));
952
953         if (inset) {
954                 y = y_tmp;
955                 return inset;
956         }
957  
958         // look at previous position
959  
960         if (cursor.pos() == 0) {
961                 return 0;
962         }
963
964         // move back one
965         text->setCursor(bv_, cursor, cursor.par(), cursor.pos() - 1, true);
966
967         inset = checkInset(*text, cursor, x, y_tmp);
968         if (inset) {
969                 y = y_tmp;
970         }
971         return inset;
972 }
973
974
975 void BufferView::Pimpl::workAreaExpose()
976 {
977         static int work_area_width;
978         static unsigned int work_area_height;
979
980         bool const widthChange = workarea_.workWidth() != work_area_width;
981         bool const heightChange = workarea_.height() != work_area_height;
982
983         // update from work area
984         work_area_width = workarea_.workWidth();
985         work_area_height = workarea_.height();
986         if (buffer_ != 0) {
987                 if (widthChange) {
988                         // The visible LyXView need a resize
989                         owner_->resize();
990
991                         // Remove all texts from the textcache
992                         // This is not _really_ what we want to do. What
993                         // we really want to do is to delete in textcache
994                         // that does not have a BufferView with matching
995                         // width, but as long as we have only one BufferView
996                         // deleting all gives the same result.
997                         if (lyxerr.debugging())
998                                 textcache.show(lyxerr, "Expose delete all");
999                         textcache.clear();
1000                 } else if (heightChange) {
1001                         // Rebuild image of current screen
1002                         updateScreen();
1003                         // fitCursor() ensures we don't jump back
1004                         // to the start of the document on vertical
1005                         // resize
1006                         fitCursor();
1007
1008                         // The main window size has changed, repaint most stuff
1009                         redraw();
1010                 } else if (screen_.get())
1011                     screen_->redraw(bv_->text, bv_);
1012         } else {
1013                 // Grey box when we don't have a buffer
1014                 workarea_.greyOut();
1015         }
1016
1017         // always make sure that the scrollbar is sane.
1018         updateScrollbar();
1019         owner_->updateLayoutChoice();
1020         return;
1021 }
1022
1023
1024 void BufferView::Pimpl::update()
1025 {
1026         if (screen_.get() &&
1027                 (!bv_->theLockingInset() || !bv_->theLockingInset()->nodraw()))
1028         {
1029                 LyXText::text_status st = bv_->text->status();
1030                 screen_->update(bv_->text, bv_);
1031                 bool fitc = false;
1032                 while (bv_->text->status() == LyXText::CHANGED_IN_DRAW) {
1033                         if (bv_->text->fullRebreak(bv_)) {
1034                                 st = LyXText::NEED_MORE_REFRESH;
1035                                 bv_->text->setCursor(bv_, bv_->text->cursor.par(),
1036                                                                          bv_->text->cursor.pos());
1037                                 fitc = true;
1038                         }
1039                         bv_->text->status(bv_, st);
1040                         screen_->update(bv_->text, bv_);
1041                 }
1042                 // do this here instead of in the screen::update because of
1043                 // the above loop!
1044                 bv_->text->status(bv_, LyXText::UNCHANGED);
1045                 if (fitc)
1046                         fitCursor();
1047         }
1048 }
1049
1050 // Values used when calling update:
1051 // -3 - update
1052 // -2 - update, move sel_cursor if selection, fitcursor
1053 // -1 - update, move sel_cursor if selection, fitcursor, mark dirty
1054 //  0 - update, move sel_cursor if selection, fitcursor 
1055 //  1 - update, move sel_cursor if selection, fitcursor, mark dirty
1056 //  3 - update, move sel_cursor if selection
1057 //
1058 // update -
1059 // a simple redraw of the parts that need refresh
1060 //
1061 // move sel_cursor if selection -
1062 // the text's sel_cursor is moved if there is selection is progress
1063 //
1064 // fitcursor -
1065 // fitCursor() is called and the scrollbar updated
1066 //
1067 // mark dirty -
1068 // the buffer is marked dirty.
1069 //
1070 // enum {
1071 //       UPDATE = 0,
1072 //       SELECT = 1,
1073 //       FITCUR = 2,
1074 //       CHANGE = 4 
1075 // };
1076 //
1077 // UPDATE_ONLY = UPDATE;
1078 // UPDATE_SELECT = UPDATE | SELECT;
1079 // UPDATE_SELECT_MOVE = UPDATE | SELECT | FITCUR;
1080 // UPDATE_SELECT_MOVE_AFTER_CHANGE = UPDATE | SELECT | FITCUR | CHANGE;
1081 //
1082 // update(-3) -> update(0)         -> update(0) -> update(UPDATE)
1083 // update(-2) -> update(1 + 2)     -> update(3) -> update(SELECT|FITCUR)
1084 // update(-1) -> update(1 + 2 + 4) -> update(7) -> update(SELECT|FITCUR|CHANGE)
1085 // update(1)  -> update(1 + 2 + 4) -> update(7) -> update(SELECT|FITCUR|CHANGE)
1086 // update(3)  -> update(1)         -> update(1) -> update(SELECT)
1087
1088 void BufferView::Pimpl::update(LyXText * text, BufferView::UpdateCodes f)
1089 {
1090         owner_->updateLayoutChoice();
1091
1092         if (!text->selection.set() && (f & SELECT)) {
1093                 text->selection.cursor = text->cursor;
1094         }
1095
1096         text->fullRebreak(bv_);
1097
1098         if (text->inset_owner) {
1099                 text->inset_owner->setUpdateStatus(bv_, InsetText::NONE);
1100             updateInset(text->inset_owner, false);
1101         } else {
1102             update();
1103         }
1104                 
1105         if ((f & FITCUR)) {
1106                 fitCursor();
1107         }
1108
1109         if ((f & CHANGE)) {
1110                 buffer_->markDirty();
1111         }
1112 }
1113
1114
1115 // Callback for cursor timer
1116 void BufferView::Pimpl::cursorToggle()
1117 {
1118         if (!buffer_) {
1119                 cursor_timeout.restart();
1120                 return;
1121         }
1122  
1123         if (!screen_.get()) {
1124                 cursor_timeout.restart();
1125                 return;
1126         }
1127
1128         /* FIXME */
1129         extern void reapSpellchecker(void);
1130         reapSpellchecker();
1131          
1132         if (!bv_->theLockingInset()) {
1133                 screen_->cursorToggle(bv_);
1134         } else {
1135                 bv_->theLockingInset()->toggleInsetCursor(bv_);
1136         }
1137         
1138         cursor_timeout.restart();
1139 }
1140
1141
1142 void BufferView::Pimpl::cursorPrevious(LyXText * text)
1143 {
1144         if (!text->cursor.row()->previous())
1145                 return;
1146         
1147         int y = text->first_y;
1148         if (text->inset_owner)
1149                 y += bv_->text->first_y;
1150         Row * cursorrow = text->cursor.row();
1151         text->setCursorFromCoordinates(bv_, bv_->text->cursor.x_fix(), y);
1152         finishUndo();
1153         // This is to allow jumping over large insets
1154         if ((cursorrow == text->cursor.row()))
1155                 text->cursorUp(bv_);
1156         
1157         if (text->inset_owner ||
1158             text->cursor.row()->height() < workarea_.height())
1159                 screen_->draw(bv_->text, bv_,
1160                               text->cursor.y()
1161                               - text->cursor.row()->baseline()
1162                               + text->cursor.row()->height()
1163                               - workarea_.height() + 1);
1164         updateScrollbar();
1165 }
1166
1167
1168 void BufferView::Pimpl::cursorNext(LyXText * text)
1169 {
1170         if (!text->cursor.row()->next())
1171                 return;
1172         
1173         int y = text->first_y + workarea_.height();
1174 //      if (text->inset_owner)
1175 //              y += bv_->text->first;
1176         text->getRowNearY(y);
1177     
1178         Row * cursorrow = text->cursor.row();
1179         text->setCursorFromCoordinates(bv_, text->cursor.x_fix(), y); // + workarea_->height());
1180         finishUndo();
1181         // This is to allow jumping over large insets
1182         if ((cursorrow == bv_->text->cursor.row()))
1183                 text->cursorDown(bv_);
1184         
1185         if (text->inset_owner ||
1186             text->cursor.row()->height() < workarea_.height())
1187                 screen_->draw(bv_->text, bv_, text->cursor.y() -
1188                               text->cursor.row()->baseline());
1189         updateScrollbar();
1190 }
1191
1192
1193 bool BufferView::Pimpl::available() const
1194 {
1195         if (buffer_ && bv_->text) return true;
1196         return false;
1197 }
1198
1199
1200 void BufferView::Pimpl::beforeChange(LyXText * text)
1201 {
1202         toggleSelection();
1203         text->clearSelection();
1204 }
1205
1206
1207 void BufferView::Pimpl::savePosition(unsigned int i)
1208 {
1209         if (i >= saved_positions_num)
1210                 return;
1211         saved_positions[i] = Position(buffer_->fileName(),
1212                                       bv_->text->cursor.par()->id(),
1213                                       bv_->text->cursor.pos());
1214         if (i > 0) {
1215                 ostringstream str;
1216                 str << _("Saved bookmark") << ' ' << i;
1217                 owner_->message(str.str().c_str());
1218         }
1219 }
1220
1221
1222 void BufferView::Pimpl::restorePosition(unsigned int i)
1223 {
1224         if (i >= saved_positions_num)
1225                 return;
1226
1227         string const fname = saved_positions[i].filename;
1228
1229         beforeChange(bv_->text);
1230
1231         if (fname != buffer_->fileName()) {
1232                 Buffer * b = bufferlist.exists(fname) ?
1233                         bufferlist.getBuffer(fname) :
1234                         bufferlist.loadLyXFile(fname); // don't ask, just load it
1235                 if (b != 0) buffer(b);
1236         }
1237
1238         Paragraph * par = buffer_->getParFromID(saved_positions[i].par_id);
1239         if (!par)
1240                 return;
1241
1242         bv_->text->setCursor(bv_, par,
1243                              min(par->size(), saved_positions[i].par_pos));
1244
1245         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1246         if (i > 0) {
1247                 ostringstream str;
1248                 str << _("Moved to bookmark") << ' ' << i;
1249                 owner_->message(str.str().c_str());
1250         }
1251 }
1252
1253
1254 bool BufferView::Pimpl::isSavedPosition(unsigned int i)
1255 {
1256         if (i >= saved_positions_num)
1257                 return false;
1258
1259         return !saved_positions[i].filename.empty();
1260 }
1261
1262
1263 void BufferView::Pimpl::setState()
1264 {
1265         if (!lyxrc.rtl_support)
1266                 return;
1267
1268         LyXText * text = bv_->getLyXText();
1269         if (text->real_current_font.isRightToLeft()) {
1270                 if (owner_->getIntl()->keymap == Intl::PRIMARY)
1271                         owner_->getIntl()->KeyMapSec();
1272         } else {
1273                 if (owner_->getIntl()->keymap == Intl::SECONDARY)
1274                         owner_->getIntl()->KeyMapPrim();
1275         }
1276 }
1277
1278
1279 void BufferView::Pimpl::insetSleep()
1280 {
1281         if (bv_->theLockingInset() && !inset_slept) {
1282                 bv_->theLockingInset()->getCursorPos(bv_, bv_->slx, bv_->sly);
1283                 bv_->theLockingInset()->insetUnlock(bv_);
1284                 inset_slept = true;
1285         }
1286 }
1287
1288
1289 void BufferView::Pimpl::insetWakeup()
1290 {
1291         if (bv_->theLockingInset() && inset_slept) {
1292                 bv_->theLockingInset()->edit(bv_, bv_->slx, bv_->sly, 0);
1293                 inset_slept = false;
1294         }
1295 }
1296
1297
1298 void BufferView::Pimpl::insetUnlock()
1299 {
1300         if (bv_->theLockingInset()) {
1301                 if (!inset_slept)
1302                         bv_->theLockingInset()->insetUnlock(bv_);
1303                 bv_->theLockingInset(0);
1304                 finishUndo();
1305                 inset_slept = false;
1306         }
1307 }
1308
1309
1310 bool BufferView::Pimpl::focus() const
1311 {
1312         return workarea_.hasFocus();
1313 }
1314
1315
1316 void BufferView::Pimpl::focus(bool f)
1317 {
1318         if (f) workarea_.setFocus();
1319 }
1320
1321
1322 bool BufferView::Pimpl::active() const
1323 {
1324         return workarea_.active();
1325 }
1326
1327
1328 bool BufferView::Pimpl::belowMouse() const 
1329 {
1330         return workarea_.belowMouse();
1331 }
1332
1333
1334 void BufferView::Pimpl::showCursor()
1335 {
1336         if (screen_.get()) {
1337                 if (bv_->theLockingInset())
1338                         bv_->theLockingInset()->showInsetCursor(bv_);
1339                 else
1340                         screen_->showCursor(bv_->text, bv_);
1341         }
1342 }
1343
1344
1345 void BufferView::Pimpl::hideCursor()
1346 {
1347         if (screen_.get()) {
1348                 if (!bv_->theLockingInset())
1349 //                      bv_->theLockingInset()->hideInsetCursor(bv_);
1350 //              else
1351                         screen_->hideCursor();
1352         }
1353 }
1354
1355
1356 void BufferView::Pimpl::toggleSelection(bool b)
1357 {
1358         if (screen_.get()) {
1359                 if (bv_->theLockingInset())
1360                         bv_->theLockingInset()->toggleSelection(bv_, b);
1361                 screen_->toggleSelection(bv_->text, bv_, b);
1362         }
1363 }
1364
1365
1366 void BufferView::Pimpl::toggleToggle()
1367 {
1368         if (screen_.get())
1369                 screen_->toggleToggle(bv_->text, bv_);
1370 }
1371
1372
1373 void BufferView::Pimpl::center() 
1374 {
1375         beforeChange(bv_->text);
1376         if (bv_->text->cursor.y() > static_cast<int>((workarea_.height() / 2))) {
1377                 screen_->draw(bv_->text, bv_, bv_->text->cursor.y() - workarea_.height() / 2);
1378         } else {
1379                 screen_->draw(bv_->text, bv_, 0);
1380         }
1381         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1382         redraw();
1383 }
1384
1385
1386 void BufferView::Pimpl::pasteClipboard(bool asPara) 
1387 {
1388         if (!buffer_) return;
1389
1390         screen_->hideCursor();
1391         beforeChange(bv_->text);
1392         
1393         string const clip(workarea_.getClipboard());
1394         
1395         if (clip.empty()) return;
1396
1397         if (asPara) {
1398                 bv_->getLyXText()->insertStringAsParagraphs(bv_, clip);
1399         } else {
1400                 bv_->getLyXText()->insertStringAsLines(bv_, clip);
1401         }
1402         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1403 }
1404
1405
1406 void BufferView::Pimpl::stuffClipboard(string const & stuff) const
1407 {
1408         workarea_.putClipboard(stuff);
1409 }
1410
1411
1412 /*
1413  * Dispatch functions for actions which can be valid for BufferView->text
1414  * and/or InsetText->text!!!
1415  */
1416
1417
1418 inline
1419 void BufferView::Pimpl::moveCursorUpdate(bool selecting)
1420 {
1421         LyXText * lt = bv_->getLyXText();
1422         
1423         if (selecting || lt->selection.mark()) {
1424                 lt->setSelection(bv_);
1425                 if (lt->bv_owner)
1426                         toggleToggle();
1427         }
1428         update(lt, BufferView::SELECT|BufferView::FITCUR);
1429         showCursor();
1430         
1431         /* ---> Everytime the cursor is moved, show the current font state. */
1432         // should this too me moved out of this func?
1433         //owner->showState();
1434         setState();
1435 }
1436
1437
1438 Inset * BufferView::Pimpl::getInsetByCode(Inset::Code code)
1439 {
1440         LyXCursor cursor = bv_->getLyXText()->cursor;
1441         Buffer::inset_iterator it =
1442                 find_if(Buffer::inset_iterator(
1443                         cursor.par(), cursor.pos()),
1444                         buffer_->inset_iterator_end(),
1445                         lyx::compare_memfun(&Inset::lyxCode, code));
1446         return it != buffer_->inset_iterator_end() ? (*it) : 0;
1447 }
1448
1449
1450 void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
1451 {
1452         string filename = filen;
1453
1454         if (filename.empty()) {
1455                 // Launch a file browser
1456                 string initpath = lyxrc.document_path;
1457
1458                 if (available()) {
1459                         string const trypath = owner_->buffer()->filePath();
1460                         // If directory is writeable, use this as default.
1461                         if (IsDirWriteable(trypath))
1462                                 initpath = trypath;
1463                 }
1464
1465                 FileDialog fileDlg(bv_->owner(),
1466                                    _("Select LyX document to insert"),
1467                         LFUN_FILE_INSERT,
1468                         make_pair(string(_("Documents|#o#O")),
1469                                   string(lyxrc.document_path)),
1470                         make_pair(string(_("Examples|#E#e")),
1471                                   string(AddPath(system_lyxdir, "examples"))));
1472
1473                 FileDialog::Result result =
1474                         fileDlg.Select(initpath,
1475                                        _("*.lyx| LyX Documents (*.lyx)"));
1476  
1477                 if (result.first == FileDialog::Later)
1478                         return;
1479
1480                 filename = result.second;
1481
1482                 // check selected filename
1483                 if (filename.empty()) {
1484                         owner_->message(_("Canceled."));
1485                         return;
1486                 }
1487         }
1488
1489         // get absolute path of file and add ".lyx" to the filename if
1490         // necessary
1491         filename = FileSearch(string(), filename, "lyx");
1492
1493         string const disp_fn(MakeDisplayPath(filename));
1494         
1495         ostringstream s1;
1496         s1 << _("Inserting document") << ' '
1497            << disp_fn << " ...";
1498         owner_->message(s1.str().c_str());
1499         bool const res = bv_->insertLyXFile(filename);
1500         if (res) {
1501                 ostringstream str;
1502                 str << _("Document") << ' ' << disp_fn
1503                     << ' ' << _("inserted.");
1504                 owner_->message(str.str().c_str());
1505         } else {
1506                 ostringstream str;
1507                 str << _("Could not insert document") << ' '
1508                     << disp_fn;
1509                 owner_->message(str.str().c_str());
1510         }
1511 }
1512
1513
1514 bool BufferView::Pimpl::Dispatch(kb_action action, string const & argument)
1515 {
1516         lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch: action["
1517                               << action <<"] arg[" << argument << "]" << endl;
1518         
1519         switch (action) {
1520                 // --- Misc -------------------------------------------
1521         case LFUN_APPENDIX:
1522         {
1523                 if (available()) {
1524                         LyXText * lt = bv_->getLyXText();
1525                         lt->toggleAppendix(bv_);
1526                         update(lt,
1527                                BufferView::SELECT
1528                                | BufferView::FITCUR
1529                                | BufferView::CHANGE);
1530                 }
1531         }
1532         break;
1533
1534         case LFUN_TOC_INSERT:
1535         {
1536                 InsetCommandParams p;
1537                 p.setCmdName("tableofcontents");
1538                 Inset * inset = new InsetTOC(p);
1539                 if (!insertInset(inset, "Standard"))
1540                         delete inset;
1541                 break;
1542         }
1543                 
1544         case LFUN_SCROLL_INSET:
1545                 // this is not handled here as this funktion is only aktive
1546                 // if we have a locking_inset and that one is (or contains)
1547                 // a tabular-inset
1548                 break;
1549
1550         case LFUN_INSET_GRAPHICS:
1551         {
1552                 Inset * new_inset = new InsetGraphics;
1553                 if (!insertInset(new_inset)) {
1554                         delete new_inset;
1555                 } else {
1556                         // this is need because you don't use a inset->Edit()
1557                         updateInset(new_inset, true);
1558                         new_inset->edit(bv_);
1559                 }
1560                 break;
1561         }
1562                 
1563         case LFUN_PASTE:
1564                 bv_->paste();
1565                 setState();
1566                 break;
1567                 
1568         case LFUN_PASTESELECTION:
1569         {
1570                 bool asPara = false;
1571                 if (argument == "paragraph")
1572                         asPara = true;
1573                 pasteClipboard(asPara);
1574         }
1575         break;
1576         
1577         case LFUN_CUT:
1578                 bv_->cut();
1579                 break;
1580                 
1581         case LFUN_COPY:
1582                 bv_->copy();
1583                 break;
1584                 
1585         case LFUN_LAYOUT_COPY:
1586                 bv_->copyEnvironment();
1587                 break;
1588                 
1589         case LFUN_LAYOUT_PASTE:
1590                 bv_->pasteEnvironment();
1591                 setState();
1592                 break;
1593                 
1594         case LFUN_GOTOERROR:
1595                 gotoInset(Inset::ERROR_CODE, false);
1596                 break;
1597                 
1598         case LFUN_GOTONOTE:
1599                 gotoInset(Inset::IGNORE_CODE, false);
1600                 break;
1601
1602         case LFUN_REFERENCE_GOTO:
1603         {
1604                 vector<Inset::Code> tmp;
1605                 tmp.push_back(Inset::LABEL_CODE);
1606                 tmp.push_back(Inset::REF_CODE);
1607                 gotoInset(tmp, true);
1608                 break;
1609         }
1610
1611         case LFUN_HYPHENATION:
1612                 specialChar(InsetSpecialChar::HYPHENATION);
1613                 break;
1614                 
1615         case LFUN_LIGATURE_BREAK:
1616                 specialChar(InsetSpecialChar::LIGATURE_BREAK);
1617                 break;
1618                 
1619         case LFUN_LDOTS:
1620                 specialChar(InsetSpecialChar::LDOTS);
1621                 break;
1622                 
1623         case LFUN_END_OF_SENTENCE:
1624                 specialChar(InsetSpecialChar::END_OF_SENTENCE);
1625                 break;
1626
1627         case LFUN_MENU_SEPARATOR:
1628                 specialChar(InsetSpecialChar::MENU_SEPARATOR);
1629                 break;
1630                 
1631         case LFUN_HFILL:
1632                 hfill();
1633                 break;
1634                 
1635         case LFUN_DEPTH:
1636                 changeDepth(bv_, bv_->getLyXText(), 0);
1637                 break;
1638                 
1639         case LFUN_DEPTH_MIN:
1640                 changeDepth(bv_, bv_->getLyXText(), -1);
1641                 break;
1642                 
1643         case LFUN_DEPTH_PLUS:
1644                 changeDepth(bv_, bv_->getLyXText(), 1);
1645                 break;
1646                 
1647         case LFUN_FREE:
1648                 owner_->getDialogs()->setUserFreeFont();
1649                 break;
1650
1651         case LFUN_FILE_INSERT:
1652                 MenuInsertLyXFile(argument);
1653                 break;
1654         
1655         case LFUN_FILE_INSERT_ASCII_PARA:
1656                 InsertAsciiFile(bv_, argument, true);
1657                 break;
1658
1659         case LFUN_FILE_INSERT_ASCII:
1660                 InsertAsciiFile(bv_, argument, false);
1661                 break;
1662                 
1663         case LFUN_LAYOUT:
1664         {
1665                 lyxerr[Debug::INFO] << "LFUN_LAYOUT: (arg) "
1666                                     << argument << endl;
1667                 
1668                 // Derive layout number from given argument (string)
1669                 // and current buffer's textclass (number). */    
1670                 textclass_type tclass = buffer_->params.textclass;
1671                 bool hasLayout =
1672                         textclasslist[tclass].hasLayout(argument);
1673                 string layout = argument;
1674
1675                 // If the entry is obsolete, use the new one instead.
1676                 if (hasLayout) {
1677                         string const & obs = textclasslist[tclass][layout]
1678                                 .obsoleted_by();
1679                         if (!obs.empty()) 
1680                                 layout = obs;
1681                 }
1682
1683                 if (!hasLayout) {
1684                         owner_->getLyXFunc()->setErrorMessage(
1685                                 string(N_("Layout ")) + argument +
1686                                 N_(" not known"));
1687                         break;
1688                 }
1689
1690                 if (current_layout != layout) {
1691                         LyXText * lt = bv_->getLyXText();
1692                         hideCursor();
1693                         current_layout = layout;
1694                         update(lt,
1695                                BufferView::SELECT
1696                                | BufferView::FITCUR);
1697                         lt->setLayout(bv_, layout);
1698                         owner_->setLayout(layout);
1699                         update(lt,
1700                                BufferView::SELECT
1701                                | BufferView::FITCUR
1702                                | BufferView::CHANGE);
1703                         setState();
1704                 }
1705         }
1706         break;
1707
1708         case LFUN_LANGUAGE:
1709                 lang(bv_, argument);
1710                 setState();
1711                 owner_->showState();
1712                 break;
1713
1714         case LFUN_EMPH:
1715                 emph(bv_);
1716                 owner_->showState();
1717                 break;
1718
1719         case LFUN_BOLD:
1720                 bold(bv_);
1721                 owner_->showState();
1722                 break;
1723                 
1724         case LFUN_NOUN:
1725                 noun(bv_);
1726                 owner_->showState();
1727                 break;
1728                 
1729         case LFUN_CODE:
1730                 code(bv_);
1731                 owner_->showState();
1732                 break;
1733                 
1734         case LFUN_SANS:
1735                 sans(bv_);
1736                 owner_->showState();
1737                 break;
1738                 
1739         case LFUN_ROMAN:
1740                 roman(bv_);
1741                 owner_->showState();
1742                 break;
1743                 
1744         case LFUN_DEFAULT:
1745                 styleReset(bv_);
1746                 owner_->showState();
1747                 break;
1748                 
1749         case LFUN_UNDERLINE:
1750                 underline(bv_);
1751                 owner_->showState();
1752                 break;
1753                 
1754         case LFUN_FONT_SIZE:
1755                 fontSize(bv_, argument);
1756                 owner_->showState();
1757                 break;
1758                 
1759         case LFUN_FONT_STATE:
1760                 owner_->getLyXFunc()->setMessage(currentState(bv_));
1761                 break;
1762                 
1763         case LFUN_UPCASE_WORD:
1764         {
1765                 LyXText * lt = bv_->getLyXText();
1766                 
1767                 update(lt,
1768                        BufferView::SELECT
1769                        | BufferView::FITCUR);
1770                 lt->changeCase(bv_, LyXText::text_uppercase);
1771                 if (lt->inset_owner)
1772                         updateInset(lt->inset_owner, true);
1773                 update(lt,
1774                        BufferView::SELECT
1775                        | BufferView::FITCUR
1776                        | BufferView::CHANGE);
1777         }
1778         break;
1779                 
1780         case LFUN_LOWCASE_WORD:
1781         {
1782                 LyXText * lt = bv_->getLyXText();
1783                 
1784                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1785                 lt->changeCase(bv_, LyXText::text_lowercase);
1786                 if (lt->inset_owner)
1787                         updateInset(lt->inset_owner, true);
1788                 update(lt,
1789                        BufferView::SELECT
1790                        | BufferView::FITCUR
1791                        | BufferView::CHANGE);
1792         }
1793         break;
1794                 
1795         case LFUN_CAPITALIZE_WORD:
1796         {
1797                 LyXText * lt = bv_->getLyXText();
1798                 
1799                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1800                 lt->changeCase(bv_, LyXText::text_capitalization);
1801                 if (lt->inset_owner)
1802                         updateInset(lt->inset_owner, true);
1803                 update(lt,
1804                        BufferView::SELECT
1805                        | BufferView::FITCUR
1806                        | BufferView::CHANGE);
1807         }
1808         break;
1809
1810         case LFUN_TRANSPOSE_CHARS:
1811         {
1812                 LyXText * lt = bv_->getLyXText();
1813                 
1814                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1815                 lt->transposeChars(*bv_);
1816                 if (lt->inset_owner)
1817                         updateInset(lt->inset_owner, true);
1818                 update(lt,
1819                        BufferView::SELECT
1820                        | BufferView::FITCUR
1821                        | BufferView::CHANGE);
1822         }
1823         break;
1824                 
1825                                           
1826         case LFUN_INSERT_LABEL:
1827                 MenuInsertLabel(bv_, argument);
1828                 break;
1829
1830         case LFUN_REF_INSERT:
1831                 if (argument.empty()) {
1832                         InsetCommandParams p("ref");
1833                         owner_->getDialogs()->createRef(p.getAsString());
1834                 } else {
1835                         InsetCommandParams p;
1836                         p.setFromString(argument);
1837
1838                         InsetRef * inset = new InsetRef(p, *buffer_);
1839                         if (!insertInset(inset))
1840                                 delete inset;
1841                         else
1842                                 updateInset(inset, true);
1843                 }
1844                 break;
1845
1846         case LFUN_BOOKMARK_SAVE:
1847                 savePosition(strToUnsignedInt(argument));
1848                 break;
1849
1850         case LFUN_BOOKMARK_GOTO:
1851                 restorePosition(strToUnsignedInt(argument));
1852                 break;
1853
1854         case LFUN_REF_GOTO:
1855         {
1856                 string label(argument);
1857                 if (label.empty()) {
1858                         InsetRef * inset = 
1859                                 static_cast<InsetRef*>(getInsetByCode(Inset::REF_CODE));
1860                         if (inset) {
1861                                 label = inset->getContents();
1862                                 savePosition(0);
1863                         }
1864                 }
1865                 
1866                 if (!label.empty()) {
1867                         //bv_->savePosition(0);
1868                         if (!bv_->gotoLabel(label))
1869                                 Alert::alert(_("Error"), 
1870                                            _("Couldn't find this label"), 
1871                                            _("in current document."));
1872                 }
1873         }
1874         break;
1875                 
1876                 // --- Cursor Movements -----------------------------
1877         case LFUN_RIGHT:
1878         {
1879                 LyXText * lt = bv_->getLyXText();
1880                 
1881                 bool is_rtl = lt->cursor.par()->isRightToLeftPar(buffer_->params);
1882                 if (!lt->selection.mark())
1883                         beforeChange(lt);
1884                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1885                 if (is_rtl)
1886                         lt->cursorLeft(bv_, false);
1887                 if (lt->cursor.pos() < lt->cursor.par()->size()
1888                     && lt->cursor.par()->isInset(lt->cursor.pos())
1889                     && isHighlyEditableInset(lt->cursor.par()->getInset(lt->cursor.pos()))) {
1890                         Inset * tmpinset = lt->cursor.par()->getInset(lt->cursor.pos());
1891                         owner_->getLyXFunc()->setMessage(tmpinset->editMessage());
1892                         if (is_rtl)
1893                                 tmpinset->edit(bv_, false);
1894                         else
1895                                 tmpinset->edit(bv_);
1896                         break;
1897                 }
1898                 if (!is_rtl)
1899                         lt->cursorRight(bv_, false);
1900                 finishUndo();
1901                 moveCursorUpdate(false);
1902                 owner_->showState();
1903         }
1904         break;
1905                 
1906         case LFUN_LEFT:
1907         {
1908                 // This is soooo ugly. Isn`t it possible to make
1909                 // it simpler? (Lgb)
1910                 LyXText * lt = bv_->getLyXText();
1911                 bool is_rtl = lt->cursor.par()->isRightToLeftPar(buffer_->params);
1912                 if (!lt->selection.mark())
1913                         beforeChange(lt);
1914                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1915                 LyXCursor const cur = lt->cursor;
1916                 if (!is_rtl)
1917                         lt->cursorLeft(bv_, false);
1918                 if ((is_rtl || cur != lt->cursor) && // only if really moved!
1919                     lt->cursor.pos() < lt->cursor.par()->size() &&
1920                     lt->cursor.par()->isInset(lt->cursor.pos()) &&
1921                     isHighlyEditableInset(lt->cursor.par()->getInset(lt->cursor.pos()))) {
1922                         Inset * tmpinset = lt->cursor.par()->getInset(lt->cursor.pos());
1923                         owner_->getLyXFunc()->setMessage(tmpinset->editMessage());
1924                         if (is_rtl)
1925                                 tmpinset->edit(bv_);
1926                         else
1927                                 tmpinset->edit(bv_, false);
1928                         break;
1929                 }
1930                 if  (is_rtl)
1931                         lt->cursorRight(bv_, false);
1932
1933                 finishUndo();
1934                 moveCursorUpdate(false);
1935                 owner_->showState();
1936         }
1937         break;
1938                 
1939         case LFUN_UP:
1940         {
1941                 LyXText * lt = bv_->getLyXText();
1942                 
1943                 if (!lt->selection.mark())
1944                         beforeChange(lt);
1945                 update(lt, BufferView::UPDATE);
1946                 lt->cursorUp(bv_);
1947                 finishUndo();
1948                 moveCursorUpdate(false);
1949                 owner_->showState();
1950         }
1951         break;
1952                 
1953         case LFUN_DOWN:
1954         {
1955                 LyXText * lt = bv_->getLyXText();
1956                 
1957                 if (!lt->selection.mark())
1958                         beforeChange(lt);
1959                 update(lt, BufferView::UPDATE);
1960                 lt->cursorDown(bv_);
1961                 finishUndo();
1962                 moveCursorUpdate(false);
1963                 owner_->showState();
1964         }
1965         break;
1966
1967         case LFUN_UP_PARAGRAPH:
1968         {
1969                 LyXText * lt = bv_->getLyXText();
1970                 
1971                 if (!lt->selection.mark())
1972                         beforeChange(lt);
1973                 update(lt, BufferView::UPDATE);
1974                 lt->cursorUpParagraph(bv_);
1975                 finishUndo();
1976                 moveCursorUpdate(false);
1977                 owner_->showState();
1978         }
1979         break;
1980                 
1981         case LFUN_DOWN_PARAGRAPH:
1982         {
1983                 LyXText * lt = bv_->getLyXText();
1984                 
1985                 if (!lt->selection.mark())
1986                         beforeChange(lt);
1987                 update(lt, BufferView::UPDATE);
1988                 lt->cursorDownParagraph(bv_);
1989                 finishUndo();
1990                 moveCursorUpdate(false);
1991                 owner_->showState();
1992         }
1993         break;
1994                 
1995         case LFUN_PRIOR:
1996         {
1997                 LyXText * lt = bv_->getLyXText();
1998                 
1999                 if (!lt->selection.mark())
2000                         beforeChange(lt);
2001                 update(lt, BufferView::UPDATE);
2002                 cursorPrevious(lt);
2003                 finishUndo();
2004                 moveCursorUpdate(false);
2005                 owner_->showState();
2006         }
2007         break;
2008                 
2009         case LFUN_NEXT:
2010         {
2011                 LyXText * lt = bv_->getLyXText();
2012                 
2013                 if (!lt->selection.mark())
2014                         beforeChange(lt);
2015                 update(lt, BufferView::UPDATE);
2016                 cursorNext(lt);
2017                 finishUndo();
2018                 moveCursorUpdate(false);
2019                 owner_->showState();
2020         }
2021         break;
2022                 
2023         case LFUN_HOME:
2024         {
2025                 LyXText * lt = bv_->getLyXText();
2026                 
2027                 if (!lt->selection.mark())
2028                         beforeChange(lt);
2029                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2030                 lt->cursorHome(bv_);
2031                 finishUndo();
2032                 moveCursorUpdate(false);
2033                 owner_->showState();
2034         }
2035         break;
2036                 
2037         case LFUN_END:
2038         {
2039                 LyXText * lt = bv_->getLyXText();
2040                 
2041                 if (!lt->selection.mark())
2042                         beforeChange(lt);
2043                 update(lt,
2044                        BufferView::SELECT|BufferView::FITCUR);
2045                 lt->cursorEnd(bv_);
2046                 finishUndo();
2047                 moveCursorUpdate(false);
2048                 owner_->showState();
2049         }
2050         break;
2051                 
2052         case LFUN_SHIFT_TAB:
2053         case LFUN_TAB:
2054         {
2055                 LyXText * lt = bv_->getLyXText();
2056                 
2057                 if (!lt->selection.mark())
2058                         beforeChange(lt);
2059                 update(lt,
2060                        BufferView::SELECT|BufferView::FITCUR);
2061                 lt->cursorTab(bv_);
2062                 finishUndo();
2063                 moveCursorUpdate(false);
2064                 owner_->showState();
2065         }
2066         break;
2067                 
2068         case LFUN_WORDRIGHT:
2069         {
2070                 LyXText * lt = bv_->getLyXText();
2071                 
2072                 if (!lt->selection.mark())
2073                         beforeChange(lt);
2074                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2075                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2076                         lt->cursorLeftOneWord(bv_);
2077                 else
2078                         lt->cursorRightOneWord(bv_);
2079                 finishUndo();
2080                 moveCursorUpdate(false);
2081                 owner_->showState();
2082         }
2083         break;
2084                 
2085         case LFUN_WORDLEFT:
2086         {
2087                 LyXText * lt = bv_->getLyXText();
2088                 
2089                 if (!lt->selection.mark())
2090                         beforeChange(lt);
2091                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2092                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2093                         lt->cursorRightOneWord(bv_);
2094                 else
2095                         lt->cursorLeftOneWord(bv_);
2096                 finishUndo();
2097                 moveCursorUpdate(false);
2098                 owner_->showState();
2099         }
2100         break;
2101                 
2102         case LFUN_BEGINNINGBUF:
2103         {
2104                 LyXText * lt = bv_->getLyXText();
2105                 
2106                 if (!lt->selection.mark())
2107                         beforeChange(lt);
2108                 update(lt,
2109                        BufferView::SELECT|BufferView::FITCUR);
2110                 lt->cursorTop(bv_);
2111                 finishUndo();
2112                 moveCursorUpdate(false);
2113                 owner_->showState();
2114         }
2115         break;
2116                 
2117         case LFUN_ENDBUF:
2118         {
2119                 LyXText * lt = bv_->getLyXText();
2120                 
2121                 if (!lt->selection.mark())
2122                         beforeChange(lt);
2123                 update(lt,
2124                        BufferView::SELECT|BufferView::FITCUR);
2125                 lt->cursorBottom(bv_);
2126                 finishUndo();
2127                 moveCursorUpdate(false);
2128                 owner_->showState();
2129         }
2130         break;
2131       
2132                 /* cursor selection ---------------------------- */
2133         case LFUN_RIGHTSEL:
2134         {
2135                 LyXText * lt = bv_->getLyXText();
2136                 
2137                 update(lt,
2138                        BufferView::SELECT|BufferView::FITCUR);
2139                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2140                         lt->cursorLeft(bv_);
2141                 else
2142                         lt->cursorRight(bv_);
2143                 finishUndo();
2144                 moveCursorUpdate(true);
2145                 owner_->showState();
2146         }
2147         break;
2148                 
2149         case LFUN_LEFTSEL:
2150         {
2151                 LyXText * lt = bv_->getLyXText();
2152                 
2153                 update(lt,
2154                        BufferView::SELECT|BufferView::FITCUR);
2155                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2156                         lt->cursorRight(bv_);
2157                 else
2158                         lt->cursorLeft(bv_);
2159                 finishUndo();
2160                 moveCursorUpdate(true);
2161                 owner_->showState();
2162         }
2163         break;
2164                 
2165         case LFUN_UPSEL:
2166         {
2167                 LyXText * lt = bv_->getLyXText();
2168                 
2169                 update(lt,
2170                        BufferView::SELECT|BufferView::FITCUR);
2171                 lt->cursorUp(bv_);
2172                 finishUndo();
2173                 moveCursorUpdate(true);
2174                 owner_->showState();
2175         }
2176         break;
2177                 
2178         case LFUN_DOWNSEL:
2179         {
2180                 LyXText * lt = bv_->getLyXText();
2181                 
2182                 update(lt,
2183                        BufferView::SELECT|BufferView::FITCUR);
2184                 lt->cursorDown(bv_);
2185                 finishUndo();
2186                 moveCursorUpdate(true);
2187                 owner_->showState();
2188         }
2189         break;
2190
2191         case LFUN_UP_PARAGRAPHSEL:
2192         {
2193                 LyXText * lt = bv_->getLyXText();
2194                 
2195                 update(lt,
2196                        BufferView::SELECT|BufferView::FITCUR);
2197                 lt->cursorUpParagraph(bv_);
2198                 finishUndo();
2199                 moveCursorUpdate(true);
2200                 owner_->showState();
2201         }
2202         break;
2203                 
2204         case LFUN_DOWN_PARAGRAPHSEL:
2205         {
2206                 LyXText * lt = bv_->getLyXText();
2207                 
2208                 update(lt,
2209                        BufferView::SELECT|BufferView::FITCUR);
2210                 lt->cursorDownParagraph(bv_);
2211                 finishUndo();
2212                 moveCursorUpdate(true);
2213                 owner_->showState();
2214         }
2215         break;
2216                 
2217         case LFUN_PRIORSEL:
2218         {
2219                 LyXText * lt = bv_->getLyXText();
2220                 
2221                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2222                 cursorPrevious(lt);
2223                 finishUndo();
2224                 moveCursorUpdate(true);
2225                 owner_->showState();
2226         }
2227         break;
2228                 
2229         case LFUN_NEXTSEL:
2230         {
2231                 LyXText * lt = bv_->getLyXText();
2232                 
2233                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2234                 cursorNext(lt);
2235                 finishUndo();
2236                 moveCursorUpdate(true);
2237                 owner_->showState();
2238         }
2239         break;
2240                 
2241         case LFUN_HOMESEL:
2242         {
2243                 LyXText * lt = bv_->getLyXText();
2244                 
2245                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2246                 lt->cursorHome(bv_);
2247                 finishUndo();
2248                 moveCursorUpdate(true);
2249                 owner_->showState();
2250         }
2251         break;
2252                 
2253         case LFUN_ENDSEL:
2254         {
2255                 LyXText * lt = bv_->getLyXText();
2256                 
2257                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2258                 lt->cursorEnd(bv_);
2259                 finishUndo();
2260                 moveCursorUpdate(true);
2261                 owner_->showState();
2262         }
2263         break;
2264                 
2265         case LFUN_WORDRIGHTSEL:
2266         {
2267                 LyXText * lt = bv_->getLyXText();
2268                 
2269                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2270                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2271                         lt->cursorLeftOneWord(bv_);
2272                 else
2273                         lt->cursorRightOneWord(bv_);
2274                 finishUndo();
2275                 moveCursorUpdate(true);
2276                 owner_->showState();
2277         }
2278         break;
2279                 
2280         case LFUN_WORDLEFTSEL:
2281         {
2282                 LyXText * lt = bv_->getLyXText();
2283                 
2284                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2285                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2286                         lt->cursorRightOneWord(bv_);
2287                 else
2288                         lt->cursorLeftOneWord(bv_);
2289                 finishUndo();
2290                 moveCursorUpdate(true);
2291                 owner_->showState();
2292         }
2293         break;
2294                 
2295         case LFUN_BEGINNINGBUFSEL:
2296         {
2297                 LyXText * lt = bv_->getLyXText();
2298                 
2299                 if (lt->inset_owner)
2300                         break;
2301                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2302                 lt->cursorTop(bv_);
2303                 finishUndo();
2304                 moveCursorUpdate(true);
2305                 owner_->showState();
2306         }
2307         break;
2308                 
2309         case LFUN_ENDBUFSEL:
2310         {
2311                 LyXText * lt = bv_->getLyXText();
2312                 
2313                 if (lt->inset_owner)
2314                         break;
2315                 update(lt,
2316                        BufferView::SELECT|BufferView::FITCUR);
2317                 lt->cursorBottom(bv_);
2318                 finishUndo();
2319                 moveCursorUpdate(true);
2320                 owner_->showState();
2321         }
2322         break;
2323
2324                 // --- text changing commands ------------------------
2325         case LFUN_BREAKLINE:
2326         {
2327                 LyXText * lt = bv_->getLyXText();
2328
2329                 beforeChange(lt);
2330                 lt->insertChar(bv_, Paragraph::META_NEWLINE);
2331                 update(lt,
2332                        BufferView::SELECT
2333                        | BufferView::FITCUR
2334                        | BufferView::CHANGE);
2335                 moveCursorUpdate(false);
2336         }
2337         break;
2338                 
2339         case LFUN_PROTECTEDSPACE:
2340         {
2341                 LyXText * lt = bv_->getLyXText();
2342
2343                 LyXLayout const & style = textclasslist[buffer_->params.textclass][lt->cursor.par()->layout()];
2344
2345                 if (style.free_spacing) {
2346                         lt->insertChar(bv_, ' ');
2347                         update(lt,
2348                                BufferView::SELECT
2349                                | BufferView::FITCUR
2350                                | BufferView::CHANGE);
2351                 } else {
2352                         protectedBlank(lt);
2353                 }
2354                 moveCursorUpdate(false);
2355         }
2356         break;
2357                 
2358         case LFUN_SETMARK:
2359         {
2360                 LyXText * lt = bv_->getLyXText();
2361
2362                 if (lt->selection.mark()) {
2363                         beforeChange(lt);
2364                         update(lt,
2365                                BufferView::SELECT
2366                                | BufferView::FITCUR);
2367                         owner_->getLyXFunc()->setMessage(N_("Mark removed"));
2368                 } else {
2369                         beforeChange(lt);
2370                         lt->selection.mark(true);
2371                         update(lt,
2372                                BufferView::SELECT
2373                                | BufferView::FITCUR);
2374                         owner_->getLyXFunc()->setMessage(N_("Mark set"));
2375                 }
2376                 lt->selection.cursor = lt->cursor;
2377         }
2378         break;
2379                 
2380         case LFUN_DELETE:
2381         {
2382                 LyXText * lt = bv_->getLyXText();
2383
2384                 if (!lt->selection.set()) {
2385                         lt->Delete(bv_);
2386                         lt->selection.cursor = lt->cursor;
2387                         update(lt,
2388                                BufferView::SELECT
2389                                | BufferView::FITCUR
2390                                | BufferView::CHANGE);
2391                         // It is possible to make it a lot faster still
2392                         // just comment out the line below...
2393                         showCursor();
2394                 } else {
2395                         bv_->cut(false);
2396                 }
2397                 moveCursorUpdate(false);
2398                 owner_->showState();
2399                 setState();
2400         }
2401         break;
2402
2403         case LFUN_DELETE_SKIP:
2404         {
2405                 LyXText * lt = bv_->getLyXText();
2406
2407                 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
2408                 
2409                 LyXCursor cursor = lt->cursor;
2410
2411                 if (!lt->selection.set()) {
2412                         if (cursor.pos() == cursor.par()->size()) {
2413                                 lt->cursorRight(bv_);
2414                                 cursor = lt->cursor;
2415                                 if (cursor.pos() == 0
2416                                     && !(cursor.par()->params().spaceTop()
2417                                          == VSpace (VSpace::NONE))) {
2418                                         lt->setParagraph
2419                                                 (bv_,
2420                                                  cursor.par()->params().lineTop(),
2421                                                  cursor.par()->params().lineBottom(),
2422                                                  cursor.par()->params().pagebreakTop(), 
2423                                                  cursor.par()->params().pagebreakBottom(),
2424                                                  VSpace(VSpace::NONE), 
2425                                                  cursor.par()->params().spaceBottom(),
2426                                                  cursor.par()->params().spacing(), 
2427                                                  cursor.par()->params().align(), 
2428                                                  cursor.par()->params().labelWidthString(), 0);
2429                                         lt->cursorLeft(bv_);
2430                                         update(lt, 
2431                                                BufferView::SELECT
2432                                                | BufferView::FITCUR
2433                                                | BufferView::CHANGE);
2434                                 } else {
2435                                         lt->cursorLeft(bv_);
2436                                         lt->Delete(bv_);
2437                                         lt->selection.cursor = lt->cursor;
2438                                         update(lt,
2439                                                BufferView::SELECT
2440                                                | BufferView::FITCUR
2441                                                | BufferView::CHANGE);
2442                                 }
2443                         } else {
2444                                 lt->Delete(bv_);
2445                                 lt->selection.cursor = lt->cursor;
2446                                 update(lt,
2447                                        BufferView::SELECT
2448                                        | BufferView::FITCUR
2449                                        | BufferView::CHANGE);
2450                         }
2451                 } else {
2452                         bv_->cut(false);
2453                 }
2454         }
2455         break;
2456
2457         /* -------> Delete word forward. */
2458         case LFUN_DELETE_WORD_FORWARD:
2459                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
2460                 bv_->getLyXText()->deleteWordForward(bv_);
2461                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2462                 moveCursorUpdate(false);
2463                 owner_->showState();
2464                 break;
2465
2466                 /* -------> Delete word backward. */
2467         case LFUN_DELETE_WORD_BACKWARD:
2468         {
2469                 LyXText * lt = bv_->getLyXText();
2470                 
2471                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2472                 lt->deleteWordBackward(bv_);
2473                 update(lt,
2474                        BufferView::SELECT
2475                        | BufferView::FITCUR
2476                        | BufferView::CHANGE);
2477                 moveCursorUpdate(false);
2478                 owner_->showState();
2479         }
2480         break;
2481                 
2482                 /* -------> Kill to end of line. */
2483         case LFUN_DELETE_LINE_FORWARD:
2484         {
2485                 LyXText * lt = bv_->getLyXText();
2486                 
2487                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2488                 lt->deleteLineForward(bv_);
2489                 update(lt,
2490                        BufferView::SELECT
2491                        | BufferView::FITCUR
2492                        | BufferView::CHANGE);
2493                 moveCursorUpdate(false);
2494         }
2495         break;
2496                 
2497                 /* -------> Set mark off. */
2498         case LFUN_MARK_OFF:
2499         {
2500                 LyXText * lt = bv_->getLyXText();
2501                 
2502                 beforeChange(lt);
2503                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2504                 lt->selection.cursor = lt->cursor;
2505                 owner_->getLyXFunc()->setMessage(N_("Mark off"));
2506         }
2507         break;
2508
2509                 /* -------> Set mark on. */
2510         case LFUN_MARK_ON:
2511         {
2512                 LyXText * lt = bv_->getLyXText();
2513                 
2514                 beforeChange(lt);
2515                 lt->selection.mark(true);
2516                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2517                 lt->selection.cursor = lt->cursor;
2518                 owner_->getLyXFunc()->setMessage(N_("Mark on"));
2519         }
2520         break;
2521                 
2522         case LFUN_BACKSPACE:
2523         {
2524                 LyXText * lt = bv_->getLyXText();
2525                 
2526                 if (!lt->selection.set()) {
2527                         if (owner_->getIntl()->getTrans().backspace()) {
2528                                 lt->backspace(bv_);
2529                                 lt->selection.cursor = lt->cursor;
2530                                 update(lt,
2531                                        BufferView::SELECT
2532                                        | BufferView::FITCUR
2533                                        | BufferView::CHANGE);
2534                                 // It is possible to make it a lot faster still
2535                                 // just comment out the line below...
2536                                 showCursor();
2537                         }
2538                 } else {
2539                         bv_->cut(false);
2540                 }
2541                 owner_->showState();
2542                 setState();
2543         }
2544         break;
2545
2546         case LFUN_BACKSPACE_SKIP:
2547         {
2548                 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
2549                 LyXText * lt = bv_->getLyXText();
2550                 
2551                 LyXCursor cursor = lt->cursor;
2552                 
2553                 if (!lt->selection.set()) {
2554                         if (cursor.pos() == 0 
2555                             && !(cursor.par()->params().spaceTop() 
2556                                  == VSpace (VSpace::NONE))) {
2557                                 lt->setParagraph 
2558                                         (bv_,
2559                                          cursor.par()->params().lineTop(),      
2560                                          cursor.par()->params().lineBottom(),
2561                                          cursor.par()->params().pagebreakTop(), 
2562                                          cursor.par()->params().pagebreakBottom(),
2563                                          VSpace(VSpace::NONE), cursor.par()->params().spaceBottom(),
2564                                          cursor.par()->params().spacing(), 
2565                                          cursor.par()->params().align(), 
2566                                          cursor.par()->params().labelWidthString(), 0);
2567                                 update(lt,
2568                                        BufferView::SELECT
2569                                        | BufferView::FITCUR
2570                                        | BufferView::CHANGE);
2571                         } else {
2572                                 lt->backspace(bv_);
2573                                 lt->selection.cursor = cursor;
2574                                 update(lt,
2575                                        BufferView::SELECT
2576                                        | BufferView::FITCUR
2577                                        | BufferView::CHANGE);
2578                         }
2579                 } else
2580                         bv_->cut(false);
2581         }
2582         break;
2583
2584         case LFUN_BREAKPARAGRAPH:
2585         {
2586                 LyXText * lt = bv_->getLyXText();
2587                 
2588                 beforeChange(lt);
2589                 lt->breakParagraph(bv_, 0);
2590                 update(lt,
2591                        BufferView::SELECT
2592                        | BufferView::FITCUR
2593                        | BufferView::CHANGE);
2594                 lt->selection.cursor = lt->cursor;
2595                 setState();
2596                 owner_->showState();
2597                 break;
2598         }
2599
2600         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
2601         {
2602                 LyXText * lt = bv_->getLyXText();
2603                 
2604                 beforeChange(lt);
2605                 lt->breakParagraph(bv_, 1);
2606                 update(lt,
2607                        BufferView::SELECT
2608                        | BufferView::FITCUR
2609                        | BufferView::CHANGE);
2610                 lt->selection.cursor = lt->cursor;
2611                 setState();
2612                 owner_->showState();
2613                 break;
2614         }
2615         
2616         case LFUN_BREAKPARAGRAPH_SKIP:
2617         {
2618                 // When at the beginning of a paragraph, remove
2619                 // indentation and add a "defskip" at the top.
2620                 // Otherwise, do the same as LFUN_BREAKPARAGRAPH.
2621                 LyXText * lt = bv_->getLyXText();
2622                 
2623                 LyXCursor cursor = lt->cursor;
2624                 
2625                 beforeChange(lt);
2626                 if (cursor.pos() == 0) {
2627                         if (cursor.par()->params().spaceTop() == VSpace(VSpace::NONE)) {
2628                                 lt->setParagraph
2629                                         (bv_,
2630                                          cursor.par()->params().lineTop(),
2631                                          cursor.par()->params().lineBottom(),
2632                                          cursor.par()->params().pagebreakTop(),
2633                                          cursor.par()->params().pagebreakBottom(),
2634                                          VSpace(VSpace::DEFSKIP), cursor.par()->params().spaceBottom(),
2635                                          cursor.par()->params().spacing(),
2636                                          cursor.par()->params().align(),
2637                                          cursor.par()->params().labelWidthString(), 1);
2638                                 //update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2639                         } 
2640                 }
2641                 else {
2642                         lt->breakParagraph(bv_, 0);
2643                         //update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2644                 }
2645
2646                 update(lt,
2647                        BufferView::SELECT
2648                        | BufferView::FITCUR
2649                        | BufferView::CHANGE);
2650                 lt->selection.cursor = cursor;
2651                 setState();
2652                 owner_->showState();
2653         }
2654         break;
2655
2656         case LFUN_PARAGRAPH_SPACING:
2657         {
2658                 LyXText * lt = bv_->getLyXText();
2659                 
2660                 Paragraph * par = lt->cursor.par();
2661                 Spacing::Space cur_spacing = par->params().spacing().getSpace();
2662                 float cur_value = 1.0;
2663                 if (cur_spacing == Spacing::Other) {
2664                         cur_value = par->params().spacing().getValue();
2665                 }
2666                 
2667                 istringstream istr(argument.c_str());
2668
2669                 string tmp;
2670                 istr >> tmp;
2671                 Spacing::Space new_spacing = cur_spacing;
2672                 float new_value = cur_value;
2673                 if (tmp.empty()) {
2674                         lyxerr << "Missing argument to `paragraph-spacing'"
2675                                << endl;
2676                 } else if (tmp == "single") {
2677                         new_spacing = Spacing::Single;
2678                 } else if (tmp == "onehalf") {
2679                         new_spacing = Spacing::Onehalf;
2680                 } else if (tmp == "double") {
2681                         new_spacing = Spacing::Double;
2682                 } else if (tmp == "other") {
2683                         new_spacing = Spacing::Other;
2684                         float tmpval = 0.0;
2685                         istr >> tmpval;
2686                         lyxerr << "new_value = " << tmpval << endl;
2687                         if (tmpval != 0.0)
2688                                 new_value = tmpval;
2689                 } else if (tmp == "default") {
2690                         new_spacing = Spacing::Default;
2691                 } else {
2692                         lyxerr << _("Unknown spacing argument: ")
2693                                << argument << endl;
2694                 }
2695                 if (cur_spacing != new_spacing || cur_value != new_value) {
2696                         par->params().spacing(Spacing(new_spacing, new_value));
2697                         lt->redoParagraph(bv_);
2698                         update(lt,
2699                                BufferView::SELECT
2700                                | BufferView::FITCUR
2701                                | BufferView::CHANGE);
2702                 }
2703         }
2704         break;
2705         
2706         case LFUN_INSET_TOGGLE:
2707         {
2708                 LyXText * lt = bv_->getLyXText();
2709                 hideCursor();
2710                 beforeChange(lt);
2711                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2712                 lt->toggleInset(bv_);
2713                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2714                 setState();
2715         }       
2716                 break;
2717
2718         case LFUN_QUOTE:
2719                 smartQuote();
2720                 break;
2721
2722         case LFUN_HTMLURL:
2723         case LFUN_URL:
2724         {
2725                 InsetCommandParams p;
2726                 if (action == LFUN_HTMLURL)
2727                         p.setCmdName("htmlurl");
2728                 else
2729                         p.setCmdName("url");
2730                 owner_->getDialogs()->createUrl(p.getAsString());
2731         }
2732         break;
2733         
2734         case LFUN_INSERT_URL:
2735         {
2736                 InsetCommandParams p;
2737                 p.setFromString(argument);
2738
2739                 InsetUrl * inset = new InsetUrl(p);
2740                 if (!insertInset(inset))
2741                         delete inset;
2742                 else
2743                         updateInset(inset, true);
2744         }
2745         break;
2746         
2747         case LFUN_INSET_TEXT:
2748                 insertAndEditInset(new InsetText(buffer_->params));
2749                 break;
2750         
2751         case LFUN_INSET_ERT:
2752                 insertAndEditInset(new InsetERT(buffer_->params));
2753                 break;
2754         
2755         case LFUN_INSET_EXTERNAL:
2756                 insertAndEditInset(new InsetExternal);
2757                 break;
2758         
2759         case LFUN_INSET_FOOTNOTE:
2760                 insertAndEditInset(new InsetFoot(buffer_->params));
2761                 break;
2762
2763         case LFUN_INSET_MARGINAL:
2764                 insertAndEditInset(new InsetMarginal(buffer_->params));
2765                 break;
2766
2767         case LFUN_INSET_MINIPAGE:
2768                 insertAndEditInset(new InsetMinipage(buffer_->params));
2769                 break;
2770
2771         case LFUN_INSERT_NOTE:
2772                 insertAndEditInset(new InsetNote(buffer_->params));
2773                 break;
2774
2775         case LFUN_INSET_FLOAT:
2776                 // check if the float type exist
2777                 if (floatList.typeExist(argument)) {
2778                         insertAndEditInset(new InsetFloat(buffer_->params,
2779                                                           argument));
2780                 } else {
2781                         lyxerr << "Non-existent float type: "
2782                                << argument << endl;
2783                 }
2784                 break;
2785
2786         case LFUN_INSET_WIDE_FLOAT:
2787         {
2788                 // check if the float type exist
2789                 if (floatList.typeExist(argument)) {
2790                         InsetFloat * new_inset =
2791                                 new InsetFloat(buffer_->params, argument);
2792                         new_inset->wide(true);
2793                         if (insertInset(new_inset))
2794                                 new_inset->edit(bv_);
2795                         else
2796                                 delete new_inset;
2797                 } else {
2798                         lyxerr << "Non-existent float type: "
2799                                << argument << endl;
2800                 }
2801                 
2802         }
2803         break;
2804
2805 #if 0
2806         case LFUN_INSET_LIST:
2807                 insertAndEditInset(new InsetList);
2808                 break;
2809
2810         case LFUN_INSET_THEOREM:
2811                 insertAndEditInset(new InsetTheorem);
2812                 break;
2813 #endif
2814                 
2815         case LFUN_INSET_CAPTION:
2816         {
2817                 // Do we have a locking inset...
2818                 if (bv_->theLockingInset()) {
2819                         lyxerr << "Locking inset code: "
2820                                << static_cast<int>(bv_->theLockingInset()->lyxCode());
2821                         InsetCaption * new_inset =
2822                                 new InsetCaption(buffer_->params);
2823                         new_inset->setOwner(bv_->theLockingInset());
2824                         new_inset->setAutoBreakRows(true);
2825                         new_inset->setDrawFrame(0, InsetText::LOCKED);
2826                         new_inset->setFrameColor(0, LColor::captionframe);
2827                         if (insertInset(new_inset))
2828                                 new_inset->edit(bv_);
2829                         else
2830                                 delete new_inset;
2831                 }
2832         }
2833         break;
2834         
2835         case LFUN_INSET_TABULAR:
2836         {
2837                 int r = 2;
2838                 int c = 2;
2839                 if (!argument.empty())
2840                         ::sscanf(argument.c_str(),"%d%d", &r, &c);
2841                 InsetTabular * new_inset =
2842                         new InsetTabular(*buffer_, r, c);
2843                 bool const rtl =
2844                         bv_->getLyXText()->real_current_font.isRightToLeft();
2845                 if (!open_new_inset(new_inset, rtl))
2846                         delete new_inset;
2847         }
2848         break;
2849
2850         // --- lyxserver commands ----------------------------
2851
2852         case LFUN_CHARATCURSOR:
2853         {
2854                 pos_type pos = bv_->getLyXText()->cursor.pos();
2855                 if (pos < bv_->getLyXText()->cursor.par()->size())
2856                         owner_->getLyXFunc()->setMessage(
2857                                 tostr(bv_->getLyXText()->cursor.par()->getChar(pos)));
2858                 else
2859                         owner_->getLyXFunc()->setMessage("EOF");
2860         }
2861         break;
2862         
2863         case LFUN_GETXY:
2864                 owner_->getLyXFunc()->setMessage(tostr(bv_->getLyXText()->cursor.x())
2865                                                  + ' '
2866                                                  + tostr(bv_->getLyXText()->cursor.y()));
2867                 break;
2868                 
2869         case LFUN_SETXY:
2870         {
2871                 int x = 0;
2872                 int y = 0;
2873                 if (::sscanf(argument.c_str(), " %d %d", &x, &y) != 2) {
2874                         lyxerr << "SETXY: Could not parse coordinates in '"
2875                                << argument << std::endl;
2876                 }
2877                 bv_->getLyXText()->setCursorFromCoordinates(bv_, x, y);
2878         }
2879         break;
2880         
2881         case LFUN_GETLAYOUT:
2882                 owner_->getLyXFunc()->setMessage(tostr(bv_->getLyXText()->cursor.par()->layout()));
2883                 break;
2884                         
2885         case LFUN_GETFONT:
2886         {
2887                 LyXFont & font = bv_->getLyXText()->current_font;
2888                 if (font.shape() == LyXFont::ITALIC_SHAPE)
2889                         owner_->getLyXFunc()->setMessage("E");
2890                 else if (font.shape() == LyXFont::SMALLCAPS_SHAPE)
2891                         owner_->getLyXFunc()->setMessage("N");
2892                 else
2893                         owner_->getLyXFunc()->setMessage("0");
2894
2895         }
2896         break;
2897
2898         // --- accented characters ---------------------------
2899                 
2900         case LFUN_UMLAUT:
2901         case LFUN_CIRCUMFLEX:
2902         case LFUN_GRAVE:
2903         case LFUN_ACUTE:
2904         case LFUN_TILDE:
2905         case LFUN_CEDILLA:
2906         case LFUN_MACRON:
2907         case LFUN_DOT:
2908         case LFUN_UNDERDOT:
2909         case LFUN_UNDERBAR:
2910         case LFUN_CARON:
2911         case LFUN_SPECIAL_CARON:
2912         case LFUN_BREVE:
2913         case LFUN_TIE:
2914         case LFUN_HUNG_UMLAUT:
2915         case LFUN_CIRCLE:
2916         case LFUN_OGONEK:
2917                 if (argument.empty()) {
2918                         // As always...
2919                         owner_->getLyXFunc()->handleKeyFunc(action);
2920                 } else {
2921                         owner_->getLyXFunc()->handleKeyFunc(action);
2922                         owner_->getIntl()->getTrans()
2923                                 .TranslateAndInsert(argument[0], bv_->getLyXText());
2924                         update(bv_->getLyXText(),
2925                                BufferView::SELECT
2926                                | BufferView::FITCUR
2927                                | BufferView::CHANGE);
2928                 }
2929                 break;
2930         
2931         case LFUN_MATH_MACRO:
2932                 mathDispatchMathMacro(bv_, argument);
2933                 break;
2934
2935         case LFUN_MATH_DELIM:     
2936                 mathDispatchMathDelim(bv_, argument);
2937                 break;
2938
2939         case LFUN_INSERT_MATRIX:
2940                 mathDispatchInsertMatrix(bv_, argument);
2941                 break;
2942
2943         case LFUN_INSERT_MATH:
2944                 mathDispatchInsertMath(bv_, argument);
2945                 break;
2946
2947         case LFUN_MATH_IMPORT_SELECTION: // Imports LaTeX from the X selection
2948                 mathDispatchMathImportSelection(bv_, argument);
2949                 break;
2950
2951         case LFUN_MATH_DISPLAY:          // Open or create a displayed math inset
2952                 mathDispatchMathDisplay(bv_, argument);
2953                 break;
2954
2955         case LFUN_MATH_MODE:             // Open or create an inlined math inset 
2956                 mathDispatchMathMode(bv_, argument);
2957                 break;
2958                 
2959         case LFUN_GREEK:                 // Insert a single greek letter
2960                 mathDispatchGreek(bv_, argument);
2961                 break;
2962                 
2963         case LFUN_CITATION_INSERT:
2964         {
2965                 InsetCommandParams p;
2966                 p.setFromString(argument);
2967
2968                 InsetCitation * inset = new InsetCitation(p);
2969                 if (!insertInset(inset))
2970                         delete inset;
2971                 else
2972                         updateInset(inset, true);
2973         }
2974         break;
2975                     
2976         case LFUN_INSERT_BIBTEX:
2977         {   
2978                 // ale970405+lasgoutt970425
2979                 // The argument can be up to two tokens separated 
2980                 // by a space. The first one is the bibstyle.
2981                 string const db       = token(argument, ' ', 0);
2982                 string const bibstyle = token(argument, ' ', 1);
2983
2984                 InsetCommandParams p("BibTeX", db, bibstyle);
2985                 InsetBibtex * inset = new InsetBibtex(p);
2986                 
2987                 if (insertInset(inset)) {
2988                         if (argument.empty())
2989                                 inset->edit(bv_);
2990                 } else
2991                         delete inset;
2992         }
2993         break;
2994                 
2995         // BibTeX data bases
2996         case LFUN_BIBDB_ADD:
2997         {
2998                 InsetBibtex * inset = 
2999                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
3000                 if (inset) {
3001                         inset->addDatabase(argument);
3002                 }
3003         }
3004         break;
3005                     
3006         case LFUN_BIBDB_DEL:
3007         {
3008                 InsetBibtex * inset = 
3009                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
3010                 if (inset) {
3011                         inset->delDatabase(argument);
3012                 }
3013         }
3014         break;
3015         
3016         case LFUN_BIBTEX_STYLE:
3017         {
3018                 InsetBibtex * inset = 
3019                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
3020                 if (inset) {
3021                         inset->setOptions(argument);
3022                 }
3023         }
3024         break;
3025                 
3026         case LFUN_INDEX_CREATE:
3027         {
3028                 InsetCommandParams p("index");
3029                 if (argument.empty()) {
3030                         string const idxstring(bv_->getLyXText()->getStringToIndex(bv_));
3031                         p.setContents(idxstring);
3032                 } else {
3033                         p.setContents(argument);
3034                 }
3035
3036                 owner_->getDialogs()->createIndex(p.getAsString());
3037         }
3038         break;
3039                     
3040         case LFUN_INDEX_INSERT:
3041         {
3042                 InsetCommandParams p;
3043                 p.setFromString(argument);
3044                 InsetIndex * inset = new InsetIndex(p);
3045
3046                 if (!insertInset(inset))
3047                         delete inset;
3048                 else
3049                         updateInset(inset, true);
3050         }
3051         break;
3052                     
3053         case LFUN_INDEX_INSERT_LAST:
3054         {
3055                 string const idxstring(bv_->getLyXText()->getStringToIndex(bv_));
3056                 if (!idxstring.empty()) {
3057                         owner_->message(_("Word `")
3058                                         + idxstring + _(("' indexed.")));
3059                         InsetCommandParams p("index", idxstring);
3060                         InsetIndex * inset = new InsetIndex(p);
3061                         
3062                         if (!insertInset(inset))
3063                                 delete inset;
3064                         else
3065                                 updateInset(inset, true);
3066                 }
3067         }
3068         break;
3069
3070         case LFUN_INDEX_PRINT:
3071         {
3072                 InsetCommandParams p("printindex");
3073                 Inset * inset = new InsetPrintIndex(p);
3074                 if (!insertInset(inset, "Standard"))
3075                         delete inset;
3076         }
3077         break;
3078
3079         case LFUN_PARENTINSERT:
3080         {
3081                 lyxerr << "arg " << argument << endl;
3082                 InsetCommandParams p("lyxparent", argument);
3083                 Inset * inset = new InsetParent(p, *buffer_);
3084                 if (!insertInset(inset, "Standard"))
3085                         delete inset;
3086         }
3087                  
3088         break;
3089
3090         case LFUN_CHILD_INSERT:
3091         {
3092                 InsetInclude::Params p;
3093                 p.cparams.setFromString(argument);
3094                 p.masterFilename_ = buffer_->fileName();
3095
3096                 InsetInclude * inset = new InsetInclude(p);
3097                 if (!insertInset(inset))
3098                         delete inset;
3099                 else {
3100                         updateInset(inset, true);
3101                         bv_->owner()->getDialogs()->showInclude(inset);
3102                 }
3103         }
3104         break; 
3105
3106         case LFUN_FLOAT_LIST:
3107         {
3108                 // We should check the argument for validity. (Lgb)
3109                 Inset * inset = new InsetFloatList(argument);
3110                 if (!insertInset(inset, "Standard"))
3111                         delete inset;
3112         }
3113         break;
3114         
3115         case LFUN_THESAURUS_ENTRY:
3116         {
3117                 string arg = argument;
3118
3119                 if (arg.empty()) {
3120                         arg = bv_->getLyXText()->selectionAsString(buffer_,
3121                                                                    false);
3122  
3123                         // FIXME
3124                         if (arg.size() > 100 || arg.empty()) {
3125                                 // Get word or selection
3126                                 bv_->getLyXText()->selectWordWhenUnderCursor(bv_, LyXText::WHOLE_WORD);
3127                                 arg = bv_->getLyXText()->selectionAsString(buffer_, false);
3128                                 // FIXME: where is getLyXText()->unselect(bv_) ?
3129                         }
3130                 }
3131
3132                 bv_->owner()->getDialogs()->showThesaurus(arg);
3133         }
3134                 break;
3135  
3136         case LFUN_SELFINSERT:
3137         {
3138                 if (argument.empty()) break;
3139                 
3140                 /* Automatically delete the currently selected
3141                  * text and replace it with what is being
3142                  * typed in now. Depends on lyxrc settings
3143                  * "auto_region_delete", which defaults to
3144                  * true (on). */
3145
3146                 LyXText * lt = bv_->getLyXText();
3147                 
3148                 if (lyxrc.auto_region_delete) {
3149                         if (lt->selection.set()) {
3150                                 lt->cutSelection(bv_, false, false);
3151                                 bv_->update(lt,
3152                                             BufferView::SELECT
3153                                             | BufferView::FITCUR
3154                                             | BufferView::CHANGE);
3155                         }
3156                 }
3157                 
3158                 beforeChange(lt);
3159                 LyXFont const old_font(lt->real_current_font);
3160                 
3161                 string::const_iterator cit = argument.begin();
3162                 string::const_iterator end = argument.end();
3163                 for (; cit != end; ++cit) {
3164                         owner_->getIntl()->getTrans().TranslateAndInsert(*cit, lt);
3165                 }
3166                 
3167                 bv_->update(lt,
3168                             BufferView::SELECT
3169                             | BufferView::FITCUR
3170                             | BufferView::CHANGE);
3171                 
3172                 lt->selection.cursor = lt->cursor;
3173                 moveCursorUpdate(false);
3174                 
3175                 // real_current_font.number can change so we need to
3176                 // update the minibuffer
3177                 if (old_font != lt->real_current_font)
3178                         owner_->showState();
3179                 //return string();
3180         }
3181         break;
3182
3183         case LFUN_DATE_INSERT:  // jdblair: date-insert cmd
3184         {
3185                 time_t now_time_t = time(NULL);
3186                 struct tm * now_tm = localtime(&now_time_t);
3187                 setlocale(LC_TIME, "");
3188                 string arg;
3189                 if (!argument.empty())
3190                         arg = argument;
3191                 else 
3192                         arg = lyxrc.date_insert_format;
3193                 char datetmp[32];
3194                 int const datetmp_len =
3195                         ::strftime(datetmp, 32, arg.c_str(), now_tm);
3196
3197                 LyXText * lt = bv_->getLyXText();
3198                 
3199                 for (int i = 0; i < datetmp_len; i++) {
3200                         lt->insertChar(bv_, datetmp[i]);
3201                         update(lt,
3202                                BufferView::SELECT
3203                                | BufferView::FITCUR
3204                                | BufferView::CHANGE);
3205                 }
3206
3207                 lt->selection.cursor = lt->cursor;
3208                 moveCursorUpdate(false);
3209         }
3210         break;
3211
3212         case LFUN_UNKNOWN_ACTION:
3213                 owner_->getLyXFunc()->setErrorMessage(N_("Unknown function!"));
3214                 break;
3215         
3216         default:
3217                 return false;
3218         } // end of switch
3219
3220         return true;
3221 }
3222
3223
3224 void BufferView::Pimpl::newline()
3225 {
3226         if (available()) {
3227                 LyXText * lt = bv_->getLyXText();
3228                 hideCursor();
3229                 update(lt,
3230                        BufferView::SELECT
3231                        | BufferView::FITCUR);
3232                 lt->insertChar(bv_, Paragraph::META_NEWLINE);
3233                 update(lt,
3234                        BufferView::SELECT
3235                        | BufferView::FITCUR
3236                        | BufferView::CHANGE);
3237         }
3238 }
3239
3240
3241 void BufferView::Pimpl::hfill()
3242 {
3243         if (available()) {
3244                 LyXText * lt = bv_->getLyXText();
3245                 hideCursor();
3246                 update(lt,
3247                        BufferView::SELECT
3248                        | BufferView::FITCUR);
3249                 lt->insertChar(bv_, Paragraph::META_HFILL);
3250                 update(lt,
3251                        BufferView::SELECT
3252                        | BufferView::FITCUR
3253                        | BufferView::CHANGE);
3254         }
3255 }
3256
3257
3258 void BufferView::Pimpl::protectedBlank(LyXText * lt)
3259 {
3260         if (available()) {
3261                 hideCursor();
3262                 update(lt, BufferView::SELECT|BufferView::FITCUR);
3263                 InsetSpecialChar * new_inset =
3264                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
3265 #ifdef WITH_WARNINGS
3266 #warning Why is this code different from specialChar() below? (JMarc)
3267 // the code in specialChar is a generic version of what used to exist
3268 // for other special chars. I did not merge this case because of the
3269 // call to updateInset(), but what does it do?
3270 #endif
3271                 if (!insertInset(new_inset))
3272                         delete new_inset;
3273                 else
3274                         updateInset(new_inset, true);
3275         }
3276 }
3277
3278
3279 void BufferView::Pimpl::specialChar(InsetSpecialChar::Kind kind)
3280 {
3281         if (available()) {
3282                 LyXText * lt = bv_->getLyXText();
3283                 
3284                 hideCursor();
3285                 update(lt, BufferView::SELECT|BufferView::FITCUR);
3286                 InsetSpecialChar * new_inset = 
3287                         new InsetSpecialChar(kind);
3288                 if (!insertInset(new_inset))
3289                         delete new_inset;
3290         }
3291 }
3292
3293
3294 void BufferView::Pimpl::smartQuote()
3295 {
3296         LyXText const * lt = bv_->getLyXText();
3297         Paragraph const * par = lt->cursor.par();
3298         pos_type pos = lt->cursor.pos();
3299         char c;
3300
3301         if (!pos
3302             || (par->isInset(pos - 1)
3303                 && par->getInset(pos - 1)->isSpace()))
3304                 c = ' ';
3305         else
3306                 c = par->getChar(pos - 1);
3307                 
3308
3309         hideCursor();
3310
3311         LyXLayout const & style =
3312                 textclasslist[bv_->buffer()->params.textclass][par->layout()];
3313         
3314         if (style.pass_thru ||
3315                 (!insertInset(new InsetQuotes(c, bv_->buffer()->params))))
3316                 bv_->owner()->getLyXFunc()->dispatch(LFUN_SELFINSERT, "\"");
3317 }
3318
3319
3320 void BufferView::Pimpl::insertAndEditInset(Inset * inset)
3321 {
3322         if (insertInset(inset))
3323                 inset->edit(bv_);
3324         else
3325                 delete inset;
3326 }
3327
3328  
3329 // Open and lock an updatable inset
3330 bool BufferView::Pimpl::open_new_inset(UpdatableInset * new_inset, bool behind)
3331 {
3332         LyXText * lt = bv_->getLyXText();
3333         
3334         beforeChange(lt);
3335         finishUndo();
3336         if (!insertInset(new_inset)) {
3337                 delete new_inset;
3338                 return false;
3339         }
3340         new_inset->edit(bv_, !behind);
3341         return true;
3342 }
3343
3344
3345 bool BufferView::Pimpl::insertInset(Inset * inset, string const & lout)
3346 {
3347         // if we are in a locking inset we should try to insert the
3348         // inset there otherwise this is a illegal function now
3349         if (bv_->theLockingInset()) {
3350                 if (bv_->theLockingInset()->insetAllowed(inset))
3351                     return bv_->theLockingInset()->insertInset(bv_, inset);
3352                 return false;
3353         }
3354
3355         // not quite sure if we want this...
3356         setCursorParUndo(bv_);
3357         freezeUndo();
3358         
3359         beforeChange(bv_->text);
3360         if (!lout.empty()) {
3361                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3362                 bv_->text->breakParagraph(bv_);
3363                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3364
3365                 if (bv_->text->cursor.par()->size()) {
3366                         bv_->text->cursorLeft(bv_);
3367                         
3368                         bv_->text->breakParagraph(bv_);
3369                         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3370                 }
3371
3372                 string lres = lout;
3373                 LyXTextClass const & tclass =
3374                         textclasslist[buffer_->params.textclass];
3375                 bool hasLayout = tclass.hasLayout(lres);
3376                 string lay = tclass.defaultLayoutName();
3377
3378                 if (hasLayout != false) {
3379                         // layout found
3380                         lay = lres;
3381                 } else {
3382                         // layout not fount using default
3383                         lay = tclass.defaultLayoutName();
3384                 }
3385
3386                 bv_->text->setLayout(bv_, lay);
3387                 
3388                 bv_->text->setParagraph(bv_, 0, 0,
3389                                    0, 0,
3390                                    VSpace(VSpace::NONE), VSpace(VSpace::NONE),
3391                                    Spacing(),
3392                                    LYX_ALIGN_LAYOUT, 
3393                                    string(),
3394                                    0);
3395                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3396         }
3397         
3398         bv_->text->insertInset(bv_, inset);
3399         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3400
3401         unFreezeUndo();
3402         return true;
3403 }
3404
3405
3406 void BufferView::Pimpl::updateInset(Inset * inset, bool mark_dirty)
3407 {
3408         if (!inset)
3409                 return;
3410
3411         // first check for locking insets
3412         if (bv_->theLockingInset()) {
3413                 if (bv_->theLockingInset() == inset) {
3414                         if (bv_->text->updateInset(bv_, inset)) {
3415                                 update();
3416                                 if (mark_dirty) {
3417                                         buffer_->markDirty();
3418                                 }
3419                                 updateScrollbar();
3420                                 return;
3421                         }
3422                 } else if (bv_->theLockingInset()->updateInsetInInset(bv_, inset)) {
3423                         if (bv_->text->updateInset(bv_,  bv_->theLockingInset())) {
3424                                 update();
3425                                 if (mark_dirty) {
3426                                         buffer_->markDirty();
3427                                 }
3428                                 updateScrollbar();
3429                                 return;
3430                         }
3431                 }
3432         }
3433   
3434         // then check the current buffer
3435         if (available()) {
3436                 hideCursor();
3437                 update(bv_->text, BufferView::UPDATE);
3438                 if (bv_->text->updateInset(bv_, inset)) {
3439                         if (mark_dirty) {
3440                                 update(bv_->text,
3441                                        BufferView::SELECT
3442                                        | BufferView::FITCUR
3443                                        | BufferView::CHANGE);
3444                         } else {
3445                                 update(bv_->text, SELECT);
3446                         }
3447                         return;
3448                 }
3449         }
3450 }
3451
3452
3453 void BufferView::Pimpl::gotoInset(vector<Inset::Code> const & codes,
3454                                   bool same_content)
3455 {
3456         if (!available()) return;
3457         
3458         hideCursor();
3459         beforeChange(bv_->text);
3460         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3461         
3462         LyXCursor const & cursor = bv_->text->cursor;
3463  
3464         string contents;
3465         if (same_content &&
3466             cursor.par()->isInset(cursor.pos())) {
3467                 Inset const * inset = cursor.par()->getInset(cursor.pos());
3468                 if (find(codes.begin(), codes.end(), inset->lyxCode())
3469                     != codes.end())
3470                         contents =
3471                                 static_cast<InsetCommand const *>(inset)->getContents();
3472         }
3473         
3474  
3475         if (!bv_->text->gotoNextInset(bv_, codes, contents)) {
3476                 if (bv_->text->cursor.pos() 
3477                     || bv_->text->cursor.par() != bv_->text->ownerParagraph()) {
3478                         LyXCursor tmp = bv_->text->cursor;
3479                         bv_->text->cursor.par(bv_->text->ownerParagraph());
3480                         bv_->text->cursor.pos(0);
3481                         if (!bv_->text->gotoNextInset(bv_, codes, contents)) {
3482                                 bv_->text->cursor = tmp;
3483                                 bv_->owner()->message(_("No more insets"));
3484                         }
3485                 } else {
3486                         bv_->owner()->message(_("No more insets"));
3487                 }
3488         }
3489         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3490         bv_->text->selection.cursor = bv_->text->cursor;
3491 }
3492
3493
3494 void BufferView::Pimpl::gotoInset(Inset::Code code, bool same_content)
3495 {
3496         gotoInset(vector<Inset::Code>(1, code), same_content);
3497 }