]> git.lyx.org Git - lyx.git/blob - src/BufferView_pimpl.C
layout as string
[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 = 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 = 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;
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
434             || slider_size != old_slider_size) {
435                 current_scrollbar_value = bv_->text->first;
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 + height));
466         int const last = static_cast<int>((bv_->text->first + 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,
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);
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;
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         hideCursor();
760         toggleSelection();
761         bv_->getLyXText()->clearSelection();
762         showCursor(); 
763 }
764
765  
766 void BufferView::Pimpl::enterView()
767 {
768         if (active() && available()) {
769                 SetXtermCursor(workarea_.getWin());
770                 using_xterm_cursor = true;
771         }
772 }
773
774
775 void BufferView::Pimpl::leaveView()
776 {
777         if (using_xterm_cursor) {
778                 XUndefineCursor(fl_get_display(), workarea_.getWin());
779                 using_xterm_cursor = false;
780         }
781 }
782
783
784 void BufferView::Pimpl::workAreaButtonRelease(int x, int y,
785                                               unsigned int button)
786 {
787         if (!buffer_ || !screen_.get()) return;
788
789         // If we hit an inset, we have the inset coordinates in these
790         // and inset_hit points to the inset.  If we do not hit an
791         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
792         Inset * inset_hit = checkInsetHit(bv_->text, x, y);
793
794         if (bv_->theLockingInset()) {
795                 // We are in inset locking mode.
796
797                 /* LyX does a kind of work-area grabbing for insets.
798                    Only a ButtonPress Event outside the inset will 
799                    force a insetUnlock. */
800                 bv_->theLockingInset()->
801                         insetButtonRelease(bv_, x, y, button);
802                 return;
803         }
804         
805         selection_possible = false;
806         
807         if (button == 2)
808                 return;
809
810         // finish selection
811         if (button == 1) {
812                 workarea_.haveSelection(bv_->getLyXText()->selection.set());
813         }
814  
815         setState();
816         owner_->showState();
817         owner_->updateMenubar();
818         owner_->updateToolbar();
819
820         // Did we hit an editable inset?
821         if (inset_hit) {
822                 selection_possible = false;
823
824                 // if we reach this point with a selection, it
825                 // must mean we are currently selecting.
826                 // But we don't want to open the inset
827                 // because that is annoying for the user. 
828                 // So just pretend we didn't hit it.
829                 // this is OK because a "kosher" ButtonRelease
830                 // will follow a ButtonPress that clears
831                 // the selection.
832                 // Note this also fixes selection drawing
833                 // problems if we end up opening an inset
834                 if (bv_->getLyXText()->selection.set())
835                         return;
836  
837                 // CHECK fix this proper in 0.13
838                 // well, maybe 13.0 !!!!!!!!!
839
840                 // Following a ref shouldn't issue
841                 // a push on the undo-stack
842                 // anylonger, now that we have
843                 // keybindings for following
844                 // references and returning from
845                 // references.  IMHO though, it
846                 // should be the inset's own business
847                 // to push or not push on the undo
848                 // stack. They don't *have* to
849                 // alter the document...
850                 // (Joacim)
851                 // ...or maybe the SetCursorParUndo()
852                 // below isn't necessary at all anylonger?
853                 if (inset_hit->lyxCode() == Inset::REF_CODE) {
854                         setCursorParUndo(bv_);
855                 }
856
857                 owner_->message(inset_hit->editMessage());
858
859                 if (isHighlyEditableInset(inset_hit)) {
860                         // Highly editable inset, like math
861                         UpdatableInset *inset = (UpdatableInset *)inset_hit;
862                         inset->insetButtonRelease(bv_, x, y, button);
863                 } else {
864                         inset_hit->insetButtonRelease(bv_, x, y, button);
865                         inset_hit->edit(bv_, x, y, button);
866                 }
867                 return;
868         }
869
870         // Maybe we want to edit a bibitem ale970302
871         if (bv_->text->cursor.par()->bibkey && x < 20 + 
872             bibitemMaxWidth(bv_, textclasslist[buffer_->params.textclass].defaultfont())) {
873                 bv_->text->cursor.par()->bibkey->edit(bv_, 0, 0, 0);
874         }
875
876         return;
877 }
878
879
880 Box BufferView::Pimpl::insetDimensions(LyXText const & text,
881                                        LyXCursor const & cursor) const
882 {
883         Paragraph /*const*/ & par = *cursor.par();
884         pos_type const pos = cursor.pos();
885
886         lyx::Assert(par.getInset(pos));
887  
888         Inset const & inset(*par.getInset(pos));
889
890         LyXFont const & font = text.getFont(buffer_, &par, pos);
891  
892         int const width = inset.width(bv_, font);
893         int const inset_x = font.isVisibleRightToLeft()
894                 ? (cursor.x() - width) : cursor.x();
895  
896         return Box(
897                 inset_x + inset.scroll(),
898                 inset_x + width,
899                 cursor.y() - inset.ascent(bv_, font),
900                 cursor.y() + inset.descent(bv_, font));
901 }
902  
903  
904 Inset * BufferView::Pimpl::checkInset(LyXText const & text,
905                                       LyXCursor const & cursor,
906                                       int & x, int & y) const
907 {
908         pos_type const pos(cursor.pos());
909         Paragraph /*const*/ & par(*cursor.par());
910
911         if (pos >= par.size() || !par.isInset(pos)) {
912                 return 0;
913         }
914
915         Inset /*const*/ * inset = par.getInset(pos);
916  
917         if (!isEditableInset(inset)) {
918                 return 0;
919         }
920
921         Box b(insetDimensions(text, cursor));
922
923         if (!b.contained(x, y)) {
924                 lyxerr[Debug::GUI] << "Missed inset at x,y " << x << "," << y 
925                         << " box " << b << endl;
926                 return 0;
927         }
928  
929         text.setCursor(bv_, &par, pos, true);
930  
931         x -= b.x1;
932         // The origin of an inset is on the baseline
933         y -= (text.cursor.y());
934   
935         return inset;
936 }
937
938  
939 Inset * BufferView::Pimpl::checkInsetHit(LyXText * text, int & x, int & y)
940 {
941         if (!screen_.get())
942                 return 0;
943   
944         int y_tmp = y + text->first;
945  
946         LyXCursor cursor;
947         text->setCursorFromCoordinates(bv_, cursor, x, y_tmp);
948  
949         Inset * inset(checkInset(*text, cursor, x, y_tmp));
950
951         if (inset) {
952                 y = y_tmp;
953                 return inset;
954         }
955  
956         // look at previous position
957  
958         if (cursor.pos() == 0) {
959                 return 0;
960         }
961
962         // move back one
963         text->setCursor(bv_, cursor, cursor.par(), cursor.pos() - 1, true);
964
965         inset = checkInset(*text, cursor, x, y_tmp);
966         if (inset) {
967                 y = y_tmp;
968         }
969         return inset;
970 }
971
972
973 void BufferView::Pimpl::workAreaExpose()
974 {
975         static int work_area_width;
976         static unsigned int work_area_height;
977
978         bool const widthChange = workarea_.workWidth() != work_area_width;
979         bool const heightChange = workarea_.height() != work_area_height;
980
981         // update from work area
982         work_area_width = workarea_.workWidth();
983         work_area_height = workarea_.height();
984         if (buffer_ != 0) {
985                 if (widthChange) {
986                         // The visible LyXView need a resize
987                         owner_->resize();
988
989                         // Remove all texts from the textcache
990                         // This is not _really_ what we want to do. What
991                         // we really want to do is to delete in textcache
992                         // that does not have a BufferView with matching
993                         // width, but as long as we have only one BufferView
994                         // deleting all gives the same result.
995                         if (lyxerr.debugging())
996                                 textcache.show(lyxerr, "Expose delete all");
997                         textcache.clear();
998                 } else if (heightChange) {
999                         // Rebuild image of current screen
1000                         updateScreen();
1001                         // fitCursor() ensures we don't jump back
1002                         // to the start of the document on vertical
1003                         // resize
1004                         fitCursor();
1005
1006                         // The main window size has changed, repaint most stuff
1007                         redraw();
1008                 } else if (screen_.get())
1009                     screen_->redraw(bv_->text, bv_);
1010         } else {
1011                 // Grey box when we don't have a buffer
1012                 workarea_.greyOut();
1013         }
1014
1015         // always make sure that the scrollbar is sane.
1016         updateScrollbar();
1017         owner_->updateLayoutChoice();
1018         return;
1019 }
1020
1021
1022 void BufferView::Pimpl::update()
1023 {
1024         if (screen_.get() &&
1025                 (!bv_->theLockingInset() || !bv_->theLockingInset()->nodraw()))
1026         {
1027                 LyXText::text_status st = bv_->text->status();
1028                 screen_->update(bv_->text, bv_);
1029                 bool fitc = false;
1030                 while (bv_->text->status() == LyXText::CHANGED_IN_DRAW) {
1031                         if (bv_->text->fullRebreak(bv_)) {
1032                                 st = LyXText::NEED_MORE_REFRESH;
1033                                 bv_->text->setCursor(bv_, bv_->text->cursor.par(),
1034                                                                          bv_->text->cursor.pos());
1035                                 fitc = true;
1036                         }
1037                         bv_->text->status(bv_, st);
1038                         screen_->update(bv_->text, bv_);
1039                 }
1040                 // do this here instead of in the screen::update because of
1041                 // the above loop!
1042                 bv_->text->status(bv_, LyXText::UNCHANGED);
1043                 if (fitc)
1044                         fitCursor();
1045         }
1046 }
1047
1048 // Values used when calling update:
1049 // -3 - update
1050 // -2 - update, move sel_cursor if selection, fitcursor
1051 // -1 - update, move sel_cursor if selection, fitcursor, mark dirty
1052 //  0 - update, move sel_cursor if selection, fitcursor 
1053 //  1 - update, move sel_cursor if selection, fitcursor, mark dirty
1054 //  3 - update, move sel_cursor if selection
1055 //
1056 // update -
1057 // a simple redraw of the parts that need refresh
1058 //
1059 // move sel_cursor if selection -
1060 // the text's sel_cursor is moved if there is selection is progress
1061 //
1062 // fitcursor -
1063 // fitCursor() is called and the scrollbar updated
1064 //
1065 // mark dirty -
1066 // the buffer is marked dirty.
1067 //
1068 // enum {
1069 //       UPDATE = 0,
1070 //       SELECT = 1,
1071 //       FITCUR = 2,
1072 //       CHANGE = 4 
1073 // };
1074 //
1075 // UPDATE_ONLY = UPDATE;
1076 // UPDATE_SELECT = UPDATE | SELECT;
1077 // UPDATE_SELECT_MOVE = UPDATE | SELECT | FITCUR;
1078 // UPDATE_SELECT_MOVE_AFTER_CHANGE = UPDATE | SELECT | FITCUR | CHANGE;
1079 //
1080 // update(-3) -> update(0)         -> update(0) -> update(UPDATE)
1081 // update(-2) -> update(1 + 2)     -> update(3) -> update(SELECT|FITCUR)
1082 // update(-1) -> update(1 + 2 + 4) -> update(7) -> update(SELECT|FITCUR|CHANGE)
1083 // update(1)  -> update(1 + 2 + 4) -> update(7) -> update(SELECT|FITCUR|CHANGE)
1084 // update(3)  -> update(1)         -> update(1) -> update(SELECT)
1085
1086 void BufferView::Pimpl::update(LyXText * text, BufferView::UpdateCodes f)
1087 {
1088         owner_->updateLayoutChoice();
1089
1090         if (!text->selection.set() && (f & SELECT)) {
1091                 text->selection.cursor = text->cursor;
1092         }
1093
1094         text->fullRebreak(bv_);
1095
1096         if (text->inset_owner) {
1097                 text->inset_owner->setUpdateStatus(bv_, InsetText::NONE);
1098             updateInset(text->inset_owner, false);
1099         } else {
1100             update();
1101         }
1102                 
1103         if ((f & FITCUR)) {
1104                 fitCursor();
1105         }
1106
1107         if ((f & CHANGE)) {
1108                 buffer_->markDirty();
1109         }
1110 }
1111
1112
1113 // Callback for cursor timer
1114 void BufferView::Pimpl::cursorToggle()
1115 {
1116         if (!buffer_) {
1117                 cursor_timeout.restart();
1118                 return;
1119         }
1120  
1121         if (!screen_.get()) {
1122                 cursor_timeout.restart();
1123                 return;
1124         }
1125
1126         /* FIXME */
1127         extern void reapSpellchecker(void);
1128         reapSpellchecker();
1129          
1130         if (!bv_->theLockingInset()) {
1131                 screen_->cursorToggle(bv_);
1132         } else {
1133                 bv_->theLockingInset()->toggleInsetCursor(bv_);
1134         }
1135         
1136         cursor_timeout.restart();
1137 }
1138
1139
1140 void BufferView::Pimpl::cursorPrevious(LyXText * text)
1141 {
1142         if (!text->cursor.row()->previous())
1143                 return;
1144         
1145         int y = text->first;
1146         if (text->inset_owner)
1147                 y += bv_->text->first;
1148         Row * cursorrow = text->cursor.row();
1149         text->setCursorFromCoordinates(bv_, bv_->text->cursor.x_fix(), y);
1150         finishUndo();
1151         // This is to allow jumping over large insets
1152         if ((cursorrow == text->cursor.row()))
1153                 text->cursorUp(bv_);
1154         
1155         if (text->inset_owner ||
1156             text->cursor.row()->height() < workarea_.height())
1157                 screen_->draw(bv_->text, bv_,
1158                               text->cursor.y()
1159                               - text->cursor.row()->baseline()
1160                               + text->cursor.row()->height()
1161                               - workarea_.height() + 1);
1162         updateScrollbar();
1163 }
1164
1165
1166 void BufferView::Pimpl::cursorNext(LyXText * text)
1167 {
1168         if (!text->cursor.row()->next())
1169                 return;
1170         
1171         int y = text->first + workarea_.height();
1172 //      if (text->inset_owner)
1173 //              y += bv_->text->first;
1174         text->getRowNearY(y);
1175     
1176         Row * cursorrow = text->cursor.row();
1177         text->setCursorFromCoordinates(bv_, text->cursor.x_fix(), y); // + workarea_->height());
1178         finishUndo();
1179         // This is to allow jumping over large insets
1180         if ((cursorrow == bv_->text->cursor.row()))
1181                 text->cursorDown(bv_);
1182         
1183         if (text->inset_owner ||
1184             text->cursor.row()->height() < workarea_.height())
1185                 screen_->draw(bv_->text, bv_, text->cursor.y() -
1186                               text->cursor.row()->baseline());
1187         updateScrollbar();
1188 }
1189
1190
1191 bool BufferView::Pimpl::available() const
1192 {
1193         if (buffer_ && bv_->text) return true;
1194         return false;
1195 }
1196
1197
1198 void BufferView::Pimpl::beforeChange(LyXText * text)
1199 {
1200         toggleSelection();
1201         text->clearSelection();
1202 }
1203
1204
1205 void BufferView::Pimpl::savePosition(unsigned int i)
1206 {
1207         if (i >= saved_positions_num)
1208                 return;
1209         saved_positions[i] = Position(buffer_->fileName(),
1210                                       bv_->text->cursor.par()->id(),
1211                                       bv_->text->cursor.pos());
1212         if (i > 0) {
1213                 ostringstream str;
1214                 str << _("Saved bookmark") << ' ' << i;
1215                 owner_->message(str.str().c_str());
1216         }
1217 }
1218
1219
1220 void BufferView::Pimpl::restorePosition(unsigned int i)
1221 {
1222         if (i >= saved_positions_num)
1223                 return;
1224
1225         string const fname = saved_positions[i].filename;
1226
1227         beforeChange(bv_->text);
1228
1229         if (fname != buffer_->fileName()) {
1230                 Buffer * b = bufferlist.exists(fname) ?
1231                         bufferlist.getBuffer(fname) :
1232                         bufferlist.loadLyXFile(fname); // don't ask, just load it
1233                 if (b != 0) buffer(b);
1234         }
1235
1236         Paragraph * par = buffer_->getParFromID(saved_positions[i].par_id);
1237         if (!par)
1238                 return;
1239
1240         bv_->text->setCursor(bv_, par,
1241                              min(par->size(), saved_positions[i].par_pos));
1242
1243         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1244         if (i > 0) {
1245                 ostringstream str;
1246                 str << _("Moved to bookmark") << ' ' << i;
1247                 owner_->message(str.str().c_str());
1248         }
1249 }
1250
1251
1252 bool BufferView::Pimpl::isSavedPosition(unsigned int i)
1253 {
1254         if (i >= saved_positions_num)
1255                 return false;
1256
1257         return !saved_positions[i].filename.empty();
1258 }
1259
1260
1261 void BufferView::Pimpl::setState()
1262 {
1263         if (!lyxrc.rtl_support)
1264                 return;
1265
1266         LyXText * text = bv_->getLyXText();
1267         if (text->real_current_font.isRightToLeft()) {
1268                 if (owner_->getIntl()->keymap == Intl::PRIMARY)
1269                         owner_->getIntl()->KeyMapSec();
1270         } else {
1271                 if (owner_->getIntl()->keymap == Intl::SECONDARY)
1272                         owner_->getIntl()->KeyMapPrim();
1273         }
1274 }
1275
1276
1277 void BufferView::Pimpl::insetSleep()
1278 {
1279         if (bv_->theLockingInset() && !inset_slept) {
1280                 bv_->theLockingInset()->getCursorPos(bv_, bv_->slx, bv_->sly);
1281                 bv_->theLockingInset()->insetUnlock(bv_);
1282                 inset_slept = true;
1283         }
1284 }
1285
1286
1287 void BufferView::Pimpl::insetWakeup()
1288 {
1289         if (bv_->theLockingInset() && inset_slept) {
1290                 bv_->theLockingInset()->edit(bv_, bv_->slx, bv_->sly, 0);
1291                 inset_slept = false;
1292         }
1293 }
1294
1295
1296 void BufferView::Pimpl::insetUnlock()
1297 {
1298         if (bv_->theLockingInset()) {
1299                 if (!inset_slept)
1300                         bv_->theLockingInset()->insetUnlock(bv_);
1301                 bv_->theLockingInset(0);
1302                 finishUndo();
1303                 inset_slept = false;
1304         }
1305 }
1306
1307
1308 bool BufferView::Pimpl::focus() const
1309 {
1310         return workarea_.hasFocus();
1311 }
1312
1313
1314 void BufferView::Pimpl::focus(bool f)
1315 {
1316         if (f) workarea_.setFocus();
1317 }
1318
1319
1320 bool BufferView::Pimpl::active() const
1321 {
1322         return workarea_.active();
1323 }
1324
1325
1326 bool BufferView::Pimpl::belowMouse() const 
1327 {
1328         return workarea_.belowMouse();
1329 }
1330
1331
1332 void BufferView::Pimpl::showCursor()
1333 {
1334         if (screen_.get()) {
1335                 if (bv_->theLockingInset())
1336                         bv_->theLockingInset()->showInsetCursor(bv_);
1337                 else
1338                         screen_->showCursor(bv_->text, bv_);
1339         }
1340 }
1341
1342
1343 void BufferView::Pimpl::hideCursor()
1344 {
1345         if (screen_.get()) {
1346                 if (!bv_->theLockingInset())
1347 //                      bv_->theLockingInset()->hideInsetCursor(bv_);
1348 //              else
1349                         screen_->hideCursor();
1350         }
1351 }
1352
1353
1354 void BufferView::Pimpl::toggleSelection(bool b)
1355 {
1356         if (screen_.get()) {
1357                 if (bv_->theLockingInset())
1358                         bv_->theLockingInset()->toggleSelection(bv_, b);
1359                 screen_->toggleSelection(bv_->text, bv_, b);
1360         }
1361 }
1362
1363
1364 void BufferView::Pimpl::toggleToggle()
1365 {
1366         if (screen_.get())
1367                 screen_->toggleToggle(bv_->text, bv_);
1368 }
1369
1370
1371 void BufferView::Pimpl::center() 
1372 {
1373         beforeChange(bv_->text);
1374         if (bv_->text->cursor.y() > static_cast<int>((workarea_.height() / 2))) {
1375                 screen_->draw(bv_->text, bv_, bv_->text->cursor.y() - workarea_.height() / 2);
1376         } else {
1377                 screen_->draw(bv_->text, bv_, 0);
1378         }
1379         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1380         redraw();
1381 }
1382
1383
1384 void BufferView::Pimpl::pasteClipboard(bool asPara) 
1385 {
1386         if (!buffer_) return;
1387
1388         screen_->hideCursor();
1389         beforeChange(bv_->text);
1390         
1391         string const clip(workarea_.getClipboard());
1392         
1393         if (clip.empty()) return;
1394
1395         if (asPara) {
1396                 bv_->getLyXText()->insertStringAsParagraphs(bv_, clip);
1397         } else {
1398                 bv_->getLyXText()->insertStringAsLines(bv_, clip);
1399         }
1400         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1401 }
1402
1403
1404 void BufferView::Pimpl::stuffClipboard(string const & stuff) const
1405 {
1406         workarea_.putClipboard(stuff);
1407 }
1408
1409
1410 /*
1411  * Dispatch functions for actions which can be valid for BufferView->text
1412  * and/or InsetText->text!!!
1413  */
1414
1415
1416 inline
1417 void BufferView::Pimpl::moveCursorUpdate(bool selecting)
1418 {
1419         LyXText * lt = bv_->getLyXText();
1420         
1421         if (selecting || lt->selection.mark()) {
1422                 lt->setSelection(bv_);
1423                 if (lt->bv_owner)
1424                         toggleToggle();
1425         }
1426         update(lt, BufferView::SELECT|BufferView::FITCUR);
1427         showCursor();
1428         
1429         /* ---> Everytime the cursor is moved, show the current font state. */
1430         // should this too me moved out of this func?
1431         //owner->showState();
1432         setState();
1433 }
1434
1435
1436 Inset * BufferView::Pimpl::getInsetByCode(Inset::Code code)
1437 {
1438         LyXCursor cursor = bv_->getLyXText()->cursor;
1439         Buffer::inset_iterator it =
1440                 find_if(Buffer::inset_iterator(
1441                         cursor.par(), cursor.pos()),
1442                         buffer_->inset_iterator_end(),
1443                         lyx::compare_memfun(&Inset::lyxCode, code));
1444         return it != buffer_->inset_iterator_end() ? (*it) : 0;
1445 }
1446
1447
1448 void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
1449 {
1450         string filename = filen;
1451
1452         if (filename.empty()) {
1453                 // Launch a file browser
1454                 string initpath = lyxrc.document_path;
1455
1456                 if (available()) {
1457                         string const trypath = owner_->buffer()->filePath();
1458                         // If directory is writeable, use this as default.
1459                         if (IsDirWriteable(trypath))
1460                                 initpath = trypath;
1461                 }
1462
1463                 FileDialog fileDlg(bv_->owner(),
1464                                    _("Select LyX document to insert"),
1465                         LFUN_FILE_INSERT,
1466                         make_pair(string(_("Documents|#o#O")),
1467                                   string(lyxrc.document_path)),
1468                         make_pair(string(_("Examples|#E#e")),
1469                                   string(AddPath(system_lyxdir, "examples"))));
1470
1471                 FileDialog::Result result =
1472                         fileDlg.Select(initpath,
1473                                        _("*.lyx| LyX Documents (*.lyx)"));
1474  
1475                 if (result.first == FileDialog::Later)
1476                         return;
1477
1478                 filename = result.second;
1479
1480                 // check selected filename
1481                 if (filename.empty()) {
1482                         owner_->message(_("Canceled."));
1483                         return;
1484                 }
1485         }
1486
1487         // get absolute path of file and add ".lyx" to the filename if
1488         // necessary
1489         filename = FileSearch(string(), filename, "lyx");
1490
1491         string const disp_fn(MakeDisplayPath(filename));
1492         
1493         ostringstream s1;
1494         s1 << _("Inserting document") << ' '
1495            << disp_fn << " ...";
1496         owner_->message(s1.str().c_str());
1497         bool const res = bv_->insertLyXFile(filename);
1498         if (res) {
1499                 ostringstream str;
1500                 str << _("Document") << ' ' << disp_fn
1501                     << ' ' << _("inserted.");
1502                 owner_->message(str.str().c_str());
1503         } else {
1504                 ostringstream str;
1505                 str << _("Could not insert document") << ' '
1506                     << disp_fn;
1507                 owner_->message(str.str().c_str());
1508         }
1509 }
1510
1511
1512 bool BufferView::Pimpl::Dispatch(kb_action action, string const & argument)
1513 {
1514         lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch: action["
1515                               << action <<"] arg[" << argument << "]" << endl;
1516         
1517         switch (action) {
1518                 // --- Misc -------------------------------------------
1519         case LFUN_APPENDIX:
1520         {
1521                 if (available()) {
1522                         LyXText * lt = bv_->getLyXText();
1523                         lt->toggleAppendix(bv_);
1524                         update(lt,
1525                                BufferView::SELECT
1526                                | BufferView::FITCUR
1527                                | BufferView::CHANGE);
1528                 }
1529         }
1530         break;
1531
1532         case LFUN_TOC_INSERT:
1533         {
1534                 InsetCommandParams p;
1535                 p.setCmdName("tableofcontents");
1536                 Inset * inset = new InsetTOC(p);
1537                 if (!insertInset(inset, "Standard"))
1538                         delete inset;
1539                 break;
1540         }
1541                 
1542         case LFUN_SCROLL_INSET:
1543                 // this is not handled here as this funktion is only aktive
1544                 // if we have a locking_inset and that one is (or contains)
1545                 // a tabular-inset
1546                 break;
1547
1548         case LFUN_INSET_GRAPHICS:
1549         {
1550                 Inset * new_inset = new InsetGraphics;
1551                 if (!insertInset(new_inset)) {
1552                         delete new_inset;
1553                 } else {
1554                         // this is need because you don't use a inset->Edit()
1555                         updateInset(new_inset, true);
1556                         new_inset->edit(bv_);
1557                 }
1558                 break;
1559         }
1560                 
1561         case LFUN_PASTE:
1562                 bv_->paste();
1563                 setState();
1564                 break;
1565                 
1566         case LFUN_PASTESELECTION:
1567         {
1568                 bool asPara = false;
1569                 if (argument == "paragraph")
1570                         asPara = true;
1571                 pasteClipboard(asPara);
1572         }
1573         break;
1574         
1575         case LFUN_CUT:
1576                 bv_->cut();
1577                 break;
1578                 
1579         case LFUN_COPY:
1580                 bv_->copy();
1581                 break;
1582                 
1583         case LFUN_LAYOUT_COPY:
1584                 bv_->copyEnvironment();
1585                 break;
1586                 
1587         case LFUN_LAYOUT_PASTE:
1588                 bv_->pasteEnvironment();
1589                 setState();
1590                 break;
1591                 
1592         case LFUN_GOTOERROR:
1593                 gotoInset(Inset::ERROR_CODE, false);
1594                 break;
1595                 
1596         case LFUN_GOTONOTE:
1597                 gotoInset(Inset::IGNORE_CODE, false);
1598                 break;
1599
1600         case LFUN_REFERENCE_GOTO:
1601         {
1602                 vector<Inset::Code> tmp;
1603                 tmp.push_back(Inset::LABEL_CODE);
1604                 tmp.push_back(Inset::REF_CODE);
1605                 gotoInset(tmp, true);
1606                 break;
1607         }
1608
1609         case LFUN_HYPHENATION:
1610                 specialChar(InsetSpecialChar::HYPHENATION);
1611                 break;
1612                 
1613         case LFUN_LIGATURE_BREAK:
1614                 specialChar(InsetSpecialChar::LIGATURE_BREAK);
1615                 break;
1616                 
1617         case LFUN_LDOTS:
1618                 specialChar(InsetSpecialChar::LDOTS);
1619                 break;
1620                 
1621         case LFUN_END_OF_SENTENCE:
1622                 specialChar(InsetSpecialChar::END_OF_SENTENCE);
1623                 break;
1624
1625         case LFUN_MENU_SEPARATOR:
1626                 specialChar(InsetSpecialChar::MENU_SEPARATOR);
1627                 break;
1628                 
1629         case LFUN_HFILL:
1630                 hfill();
1631                 break;
1632                 
1633         case LFUN_DEPTH:
1634                 changeDepth(bv_, bv_->getLyXText(), 0);
1635                 break;
1636                 
1637         case LFUN_DEPTH_MIN:
1638                 changeDepth(bv_, bv_->getLyXText(), -1);
1639                 break;
1640                 
1641         case LFUN_DEPTH_PLUS:
1642                 changeDepth(bv_, bv_->getLyXText(), 1);
1643                 break;
1644                 
1645         case LFUN_FREE:
1646                 owner_->getDialogs()->setUserFreeFont();
1647                 break;
1648
1649         case LFUN_FILE_INSERT:
1650                 MenuInsertLyXFile(argument);
1651                 break;
1652         
1653         case LFUN_FILE_INSERT_ASCII_PARA:
1654                 InsertAsciiFile(bv_, argument, true);
1655                 break;
1656
1657         case LFUN_FILE_INSERT_ASCII:
1658                 InsertAsciiFile(bv_, argument, false);
1659                 break;
1660                 
1661         case LFUN_LAYOUT:
1662         {
1663                 lyxerr[Debug::INFO] << "LFUN_LAYOUT: (arg) "
1664                                     << argument << endl;
1665                 
1666                 // Derive layout number from given argument (string)
1667                 // and current buffer's textclass (number). */    
1668                 textclass_type tclass = buffer_->params.textclass;
1669                 bool hasLayout =
1670                         textclasslist[tclass].hasLayout(argument);
1671                 string layout = argument;
1672
1673                 // If the entry is obsolete, use the new one instead.
1674                 if (hasLayout) {
1675                         string const & obs = textclasslist[tclass][layout]
1676                                 .obsoleted_by();
1677                         if (!obs.empty()) 
1678                                 layout = obs;
1679                 }
1680
1681                 if (!hasLayout) {
1682                         owner_->getLyXFunc()->setErrorMessage(
1683                                 string(N_("Layout ")) + argument +
1684                                 N_(" not known"));
1685                         break;
1686                 }
1687
1688                 if (current_layout != layout) {
1689                         LyXText * lt = bv_->getLyXText();
1690                         hideCursor();
1691                         current_layout = layout;
1692                         update(lt,
1693                                BufferView::SELECT
1694                                | BufferView::FITCUR);
1695                         lt->setLayout(bv_, layout);
1696                         owner_->setLayout(layout);
1697                         update(lt,
1698                                BufferView::SELECT
1699                                | BufferView::FITCUR
1700                                | BufferView::CHANGE);
1701                         setState();
1702                 }
1703         }
1704         break;
1705
1706         case LFUN_LANGUAGE:
1707                 lang(bv_, argument);
1708                 setState();
1709                 owner_->showState();
1710                 break;
1711
1712         case LFUN_EMPH:
1713                 emph(bv_);
1714                 owner_->showState();
1715                 break;
1716
1717         case LFUN_BOLD:
1718                 bold(bv_);
1719                 owner_->showState();
1720                 break;
1721                 
1722         case LFUN_NOUN:
1723                 noun(bv_);
1724                 owner_->showState();
1725                 break;
1726                 
1727         case LFUN_CODE:
1728                 code(bv_);
1729                 owner_->showState();
1730                 break;
1731                 
1732         case LFUN_SANS:
1733                 sans(bv_);
1734                 owner_->showState();
1735                 break;
1736                 
1737         case LFUN_ROMAN:
1738                 roman(bv_);
1739                 owner_->showState();
1740                 break;
1741                 
1742         case LFUN_DEFAULT:
1743                 styleReset(bv_);
1744                 owner_->showState();
1745                 break;
1746                 
1747         case LFUN_UNDERLINE:
1748                 underline(bv_);
1749                 owner_->showState();
1750                 break;
1751                 
1752         case LFUN_FONT_SIZE:
1753                 fontSize(bv_, argument);
1754                 owner_->showState();
1755                 break;
1756                 
1757         case LFUN_FONT_STATE:
1758                 owner_->getLyXFunc()->setMessage(currentState(bv_));
1759                 break;
1760                 
1761         case LFUN_UPCASE_WORD:
1762         {
1763                 LyXText * lt = bv_->getLyXText();
1764                 
1765                 update(lt,
1766                        BufferView::SELECT
1767                        | BufferView::FITCUR);
1768                 lt->changeCase(bv_, LyXText::text_uppercase);
1769                 if (lt->inset_owner)
1770                         updateInset(lt->inset_owner, true);
1771                 update(lt,
1772                        BufferView::SELECT
1773                        | BufferView::FITCUR
1774                        | BufferView::CHANGE);
1775         }
1776         break;
1777                 
1778         case LFUN_LOWCASE_WORD:
1779         {
1780                 LyXText * lt = bv_->getLyXText();
1781                 
1782                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1783                 lt->changeCase(bv_, LyXText::text_lowercase);
1784                 if (lt->inset_owner)
1785                         updateInset(lt->inset_owner, true);
1786                 update(lt,
1787                        BufferView::SELECT
1788                        | BufferView::FITCUR
1789                        | BufferView::CHANGE);
1790         }
1791         break;
1792                 
1793         case LFUN_CAPITALIZE_WORD:
1794         {
1795                 LyXText * lt = bv_->getLyXText();
1796                 
1797                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1798                 lt->changeCase(bv_, LyXText::text_capitalization);
1799                 if (lt->inset_owner)
1800                         updateInset(lt->inset_owner, true);
1801                 update(lt,
1802                        BufferView::SELECT
1803                        | BufferView::FITCUR
1804                        | BufferView::CHANGE);
1805         }
1806         break;
1807
1808         case LFUN_TRANSPOSE_CHARS:
1809         {
1810                 LyXText * lt = bv_->getLyXText();
1811                 
1812                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1813                 lt->transposeChars(*bv_);
1814                 if (lt->inset_owner)
1815                         updateInset(lt->inset_owner, true);
1816                 update(lt,
1817                        BufferView::SELECT
1818                        | BufferView::FITCUR
1819                        | BufferView::CHANGE);
1820         }
1821         break;
1822                 
1823                                           
1824         case LFUN_INSERT_LABEL:
1825                 MenuInsertLabel(bv_, argument);
1826                 break;
1827
1828         case LFUN_REF_INSERT:
1829                 if (argument.empty()) {
1830                         InsetCommandParams p("ref");
1831                         owner_->getDialogs()->createRef(p.getAsString());
1832                 } else {
1833                         InsetCommandParams p;
1834                         p.setFromString(argument);
1835
1836                         InsetRef * inset = new InsetRef(p, *buffer_);
1837                         if (!insertInset(inset))
1838                                 delete inset;
1839                         else
1840                                 updateInset(inset, true);
1841                 }
1842                 break;
1843
1844         case LFUN_BOOKMARK_SAVE:
1845                 savePosition(strToUnsignedInt(argument));
1846                 break;
1847
1848         case LFUN_BOOKMARK_GOTO:
1849                 restorePosition(strToUnsignedInt(argument));
1850                 break;
1851
1852         case LFUN_REF_GOTO:
1853         {
1854                 string label(argument);
1855                 if (label.empty()) {
1856                         InsetRef * inset = 
1857                                 static_cast<InsetRef*>(getInsetByCode(Inset::REF_CODE));
1858                         if (inset) {
1859                                 label = inset->getContents();
1860                                 savePosition(0);
1861                         }
1862                 }
1863                 
1864                 if (!label.empty()) {
1865                         //bv_->savePosition(0);
1866                         if (!bv_->gotoLabel(label))
1867                                 Alert::alert(_("Error"), 
1868                                            _("Couldn't find this label"), 
1869                                            _("in current document."));
1870                 }
1871         }
1872         break;
1873                 
1874                 // --- Cursor Movements -----------------------------
1875         case LFUN_RIGHT:
1876         {
1877                 LyXText * lt = bv_->getLyXText();
1878                 
1879                 bool is_rtl = lt->cursor.par()->isRightToLeftPar(buffer_->params);
1880                 if (!lt->selection.mark())
1881                         beforeChange(lt);
1882                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1883                 if (is_rtl)
1884                         lt->cursorLeft(bv_, false);
1885                 if (lt->cursor.pos() < lt->cursor.par()->size()
1886                     && lt->cursor.par()->isInset(lt->cursor.pos())
1887                     && isHighlyEditableInset(lt->cursor.par()->getInset(lt->cursor.pos()))) {
1888                         Inset * tmpinset = lt->cursor.par()->getInset(lt->cursor.pos());
1889                         owner_->getLyXFunc()->setMessage(tmpinset->editMessage());
1890                         if (is_rtl)
1891                                 tmpinset->edit(bv_, false);
1892                         else
1893                                 tmpinset->edit(bv_);
1894                         break;
1895                 }
1896                 if (!is_rtl)
1897                         lt->cursorRight(bv_, false);
1898                 finishUndo();
1899                 moveCursorUpdate(false);
1900                 owner_->showState();
1901         }
1902         break;
1903                 
1904         case LFUN_LEFT:
1905         {
1906                 // This is soooo ugly. Isn`t it possible to make
1907                 // it simpler? (Lgb)
1908                 LyXText * lt = bv_->getLyXText();
1909                 bool is_rtl = lt->cursor.par()->isRightToLeftPar(buffer_->params);
1910                 if (!lt->selection.mark())
1911                         beforeChange(lt);
1912                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1913                 LyXCursor const cur = lt->cursor;
1914                 if (!is_rtl)
1915                         lt->cursorLeft(bv_, false);
1916                 if ((is_rtl || cur != lt->cursor) && // only if really moved!
1917                     lt->cursor.pos() < lt->cursor.par()->size() &&
1918                     lt->cursor.par()->isInset(lt->cursor.pos()) &&
1919                     isHighlyEditableInset(lt->cursor.par()->getInset(lt->cursor.pos()))) {
1920                         Inset * tmpinset = lt->cursor.par()->getInset(lt->cursor.pos());
1921                         owner_->getLyXFunc()->setMessage(tmpinset->editMessage());
1922                         if (is_rtl)
1923                                 tmpinset->edit(bv_);
1924                         else
1925                                 tmpinset->edit(bv_, false);
1926                         break;
1927                 }
1928                 if  (is_rtl)
1929                         lt->cursorRight(bv_, false);
1930
1931                 finishUndo();
1932                 moveCursorUpdate(false);
1933                 owner_->showState();
1934         }
1935         break;
1936                 
1937         case LFUN_UP:
1938         {
1939                 LyXText * lt = bv_->getLyXText();
1940                 
1941                 if (!lt->selection.mark())
1942                         beforeChange(lt);
1943                 update(lt, BufferView::UPDATE);
1944                 lt->cursorUp(bv_);
1945                 finishUndo();
1946                 moveCursorUpdate(false);
1947                 owner_->showState();
1948         }
1949         break;
1950                 
1951         case LFUN_DOWN:
1952         {
1953                 LyXText * lt = bv_->getLyXText();
1954                 
1955                 if (!lt->selection.mark())
1956                         beforeChange(lt);
1957                 update(lt, BufferView::UPDATE);
1958                 lt->cursorDown(bv_);
1959                 finishUndo();
1960                 moveCursorUpdate(false);
1961                 owner_->showState();
1962         }
1963         break;
1964
1965         case LFUN_UP_PARAGRAPH:
1966         {
1967                 LyXText * lt = bv_->getLyXText();
1968                 
1969                 if (!lt->selection.mark())
1970                         beforeChange(lt);
1971                 update(lt, BufferView::UPDATE);
1972                 lt->cursorUpParagraph(bv_);
1973                 finishUndo();
1974                 moveCursorUpdate(false);
1975                 owner_->showState();
1976         }
1977         break;
1978                 
1979         case LFUN_DOWN_PARAGRAPH:
1980         {
1981                 LyXText * lt = bv_->getLyXText();
1982                 
1983                 if (!lt->selection.mark())
1984                         beforeChange(lt);
1985                 update(lt, BufferView::UPDATE);
1986                 lt->cursorDownParagraph(bv_);
1987                 finishUndo();
1988                 moveCursorUpdate(false);
1989                 owner_->showState();
1990         }
1991         break;
1992                 
1993         case LFUN_PRIOR:
1994         {
1995                 LyXText * lt = bv_->getLyXText();
1996                 
1997                 if (!lt->selection.mark())
1998                         beforeChange(lt);
1999                 update(lt, BufferView::UPDATE);
2000                 cursorPrevious(lt);
2001                 finishUndo();
2002                 moveCursorUpdate(false);
2003                 owner_->showState();
2004         }
2005         break;
2006                 
2007         case LFUN_NEXT:
2008         {
2009                 LyXText * lt = bv_->getLyXText();
2010                 
2011                 if (!lt->selection.mark())
2012                         beforeChange(lt);
2013                 update(lt, BufferView::UPDATE);
2014                 cursorNext(lt);
2015                 finishUndo();
2016                 moveCursorUpdate(false);
2017                 owner_->showState();
2018         }
2019         break;
2020                 
2021         case LFUN_HOME:
2022         {
2023                 LyXText * lt = bv_->getLyXText();
2024                 
2025                 if (!lt->selection.mark())
2026                         beforeChange(lt);
2027                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2028                 lt->cursorHome(bv_);
2029                 finishUndo();
2030                 moveCursorUpdate(false);
2031                 owner_->showState();
2032         }
2033         break;
2034                 
2035         case LFUN_END:
2036         {
2037                 LyXText * lt = bv_->getLyXText();
2038                 
2039                 if (!lt->selection.mark())
2040                         beforeChange(lt);
2041                 update(lt,
2042                        BufferView::SELECT|BufferView::FITCUR);
2043                 lt->cursorEnd(bv_);
2044                 finishUndo();
2045                 moveCursorUpdate(false);
2046                 owner_->showState();
2047         }
2048         break;
2049                 
2050         case LFUN_SHIFT_TAB:
2051         case LFUN_TAB:
2052         {
2053                 LyXText * lt = bv_->getLyXText();
2054                 
2055                 if (!lt->selection.mark())
2056                         beforeChange(lt);
2057                 update(lt,
2058                        BufferView::SELECT|BufferView::FITCUR);
2059                 lt->cursorTab(bv_);
2060                 finishUndo();
2061                 moveCursorUpdate(false);
2062                 owner_->showState();
2063         }
2064         break;
2065                 
2066         case LFUN_WORDRIGHT:
2067         {
2068                 LyXText * lt = bv_->getLyXText();
2069                 
2070                 if (!lt->selection.mark())
2071                         beforeChange(lt);
2072                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2073                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2074                         lt->cursorLeftOneWord(bv_);
2075                 else
2076                         lt->cursorRightOneWord(bv_);
2077                 finishUndo();
2078                 moveCursorUpdate(false);
2079                 owner_->showState();
2080         }
2081         break;
2082                 
2083         case LFUN_WORDLEFT:
2084         {
2085                 LyXText * lt = bv_->getLyXText();
2086                 
2087                 if (!lt->selection.mark())
2088                         beforeChange(lt);
2089                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2090                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2091                         lt->cursorRightOneWord(bv_);
2092                 else
2093                         lt->cursorLeftOneWord(bv_);
2094                 finishUndo();
2095                 moveCursorUpdate(false);
2096                 owner_->showState();
2097         }
2098         break;
2099                 
2100         case LFUN_BEGINNINGBUF:
2101         {
2102                 LyXText * lt = bv_->getLyXText();
2103                 
2104                 if (!lt->selection.mark())
2105                         beforeChange(lt);
2106                 update(lt,
2107                        BufferView::SELECT|BufferView::FITCUR);
2108                 lt->cursorTop(bv_);
2109                 finishUndo();
2110                 moveCursorUpdate(false);
2111                 owner_->showState();
2112         }
2113         break;
2114                 
2115         case LFUN_ENDBUF:
2116         {
2117                 LyXText * lt = bv_->getLyXText();
2118                 
2119                 if (!lt->selection.mark())
2120                         beforeChange(lt);
2121                 update(lt,
2122                        BufferView::SELECT|BufferView::FITCUR);
2123                 lt->cursorBottom(bv_);
2124                 finishUndo();
2125                 moveCursorUpdate(false);
2126                 owner_->showState();
2127         }
2128         break;
2129       
2130                 /* cursor selection ---------------------------- */
2131         case LFUN_RIGHTSEL:
2132         {
2133                 LyXText * lt = bv_->getLyXText();
2134                 
2135                 update(lt,
2136                        BufferView::SELECT|BufferView::FITCUR);
2137                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2138                         lt->cursorLeft(bv_);
2139                 else
2140                         lt->cursorRight(bv_);
2141                 finishUndo();
2142                 moveCursorUpdate(true);
2143                 owner_->showState();
2144         }
2145         break;
2146                 
2147         case LFUN_LEFTSEL:
2148         {
2149                 LyXText * lt = bv_->getLyXText();
2150                 
2151                 update(lt,
2152                        BufferView::SELECT|BufferView::FITCUR);
2153                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2154                         lt->cursorRight(bv_);
2155                 else
2156                         lt->cursorLeft(bv_);
2157                 finishUndo();
2158                 moveCursorUpdate(true);
2159                 owner_->showState();
2160         }
2161         break;
2162                 
2163         case LFUN_UPSEL:
2164         {
2165                 LyXText * lt = bv_->getLyXText();
2166                 
2167                 update(lt,
2168                        BufferView::SELECT|BufferView::FITCUR);
2169                 lt->cursorUp(bv_);
2170                 finishUndo();
2171                 moveCursorUpdate(true);
2172                 owner_->showState();
2173         }
2174         break;
2175                 
2176         case LFUN_DOWNSEL:
2177         {
2178                 LyXText * lt = bv_->getLyXText();
2179                 
2180                 update(lt,
2181                        BufferView::SELECT|BufferView::FITCUR);
2182                 lt->cursorDown(bv_);
2183                 finishUndo();
2184                 moveCursorUpdate(true);
2185                 owner_->showState();
2186         }
2187         break;
2188
2189         case LFUN_UP_PARAGRAPHSEL:
2190         {
2191                 LyXText * lt = bv_->getLyXText();
2192                 
2193                 update(lt,
2194                        BufferView::SELECT|BufferView::FITCUR);
2195                 lt->cursorUpParagraph(bv_);
2196                 finishUndo();
2197                 moveCursorUpdate(true);
2198                 owner_->showState();
2199         }
2200         break;
2201                 
2202         case LFUN_DOWN_PARAGRAPHSEL:
2203         {
2204                 LyXText * lt = bv_->getLyXText();
2205                 
2206                 update(lt,
2207                        BufferView::SELECT|BufferView::FITCUR);
2208                 lt->cursorDownParagraph(bv_);
2209                 finishUndo();
2210                 moveCursorUpdate(true);
2211                 owner_->showState();
2212         }
2213         break;
2214                 
2215         case LFUN_PRIORSEL:
2216         {
2217                 LyXText * lt = bv_->getLyXText();
2218                 
2219                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2220                 cursorPrevious(lt);
2221                 finishUndo();
2222                 moveCursorUpdate(true);
2223                 owner_->showState();
2224         }
2225         break;
2226                 
2227         case LFUN_NEXTSEL:
2228         {
2229                 LyXText * lt = bv_->getLyXText();
2230                 
2231                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2232                 cursorNext(lt);
2233                 finishUndo();
2234                 moveCursorUpdate(true);
2235                 owner_->showState();
2236         }
2237         break;
2238                 
2239         case LFUN_HOMESEL:
2240         {
2241                 LyXText * lt = bv_->getLyXText();
2242                 
2243                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2244                 lt->cursorHome(bv_);
2245                 finishUndo();
2246                 moveCursorUpdate(true);
2247                 owner_->showState();
2248         }
2249         break;
2250                 
2251         case LFUN_ENDSEL:
2252         {
2253                 LyXText * lt = bv_->getLyXText();
2254                 
2255                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2256                 lt->cursorEnd(bv_);
2257                 finishUndo();
2258                 moveCursorUpdate(true);
2259                 owner_->showState();
2260         }
2261         break;
2262                 
2263         case LFUN_WORDRIGHTSEL:
2264         {
2265                 LyXText * lt = bv_->getLyXText();
2266                 
2267                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2268                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2269                         lt->cursorLeftOneWord(bv_);
2270                 else
2271                         lt->cursorRightOneWord(bv_);
2272                 finishUndo();
2273                 moveCursorUpdate(true);
2274                 owner_->showState();
2275         }
2276         break;
2277                 
2278         case LFUN_WORDLEFTSEL:
2279         {
2280                 LyXText * lt = bv_->getLyXText();
2281                 
2282                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2283                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2284                         lt->cursorRightOneWord(bv_);
2285                 else
2286                         lt->cursorLeftOneWord(bv_);
2287                 finishUndo();
2288                 moveCursorUpdate(true);
2289                 owner_->showState();
2290         }
2291         break;
2292                 
2293         case LFUN_BEGINNINGBUFSEL:
2294         {
2295                 LyXText * lt = bv_->getLyXText();
2296                 
2297                 if (lt->inset_owner)
2298                         break;
2299                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2300                 lt->cursorTop(bv_);
2301                 finishUndo();
2302                 moveCursorUpdate(true);
2303                 owner_->showState();
2304         }
2305         break;
2306                 
2307         case LFUN_ENDBUFSEL:
2308         {
2309                 LyXText * lt = bv_->getLyXText();
2310                 
2311                 if (lt->inset_owner)
2312                         break;
2313                 update(lt,
2314                        BufferView::SELECT|BufferView::FITCUR);
2315                 lt->cursorBottom(bv_);
2316                 finishUndo();
2317                 moveCursorUpdate(true);
2318                 owner_->showState();
2319         }
2320         break;
2321
2322                 // --- text changing commands ------------------------
2323         case LFUN_BREAKLINE:
2324         {
2325                 LyXText * lt = bv_->getLyXText();
2326
2327                 beforeChange(lt);
2328                 lt->insertChar(bv_, Paragraph::META_NEWLINE);
2329                 update(lt,
2330                        BufferView::SELECT
2331                        | BufferView::FITCUR
2332                        | BufferView::CHANGE);
2333                 moveCursorUpdate(false);
2334         }
2335         break;
2336                 
2337         case LFUN_PROTECTEDSPACE:
2338         {
2339                 LyXText * lt = bv_->getLyXText();
2340
2341                 LyXLayout const & style = textclasslist[buffer_->params.textclass][lt->cursor.par()->layout()];
2342
2343                 if (style.free_spacing) {
2344                         lt->insertChar(bv_, ' ');
2345                         update(lt,
2346                                BufferView::SELECT
2347                                | BufferView::FITCUR
2348                                | BufferView::CHANGE);
2349                 } else {
2350                         protectedBlank(lt);
2351                 }
2352                 moveCursorUpdate(false);
2353         }
2354         break;
2355                 
2356         case LFUN_SETMARK:
2357         {
2358                 LyXText * lt = bv_->getLyXText();
2359
2360                 if (lt->selection.mark()) {
2361                         beforeChange(lt);
2362                         update(lt,
2363                                BufferView::SELECT
2364                                | BufferView::FITCUR);
2365                         owner_->getLyXFunc()->setMessage(N_("Mark removed"));
2366                 } else {
2367                         beforeChange(lt);
2368                         lt->selection.mark(true);
2369                         update(lt,
2370                                BufferView::SELECT
2371                                | BufferView::FITCUR);
2372                         owner_->getLyXFunc()->setMessage(N_("Mark set"));
2373                 }
2374                 lt->selection.cursor = lt->cursor;
2375         }
2376         break;
2377                 
2378         case LFUN_DELETE:
2379         {
2380                 LyXText * lt = bv_->getLyXText();
2381
2382                 if (!lt->selection.set()) {
2383                         lt->Delete(bv_);
2384                         lt->selection.cursor = lt->cursor;
2385                         update(lt,
2386                                BufferView::SELECT
2387                                | BufferView::FITCUR
2388                                | BufferView::CHANGE);
2389                         // It is possible to make it a lot faster still
2390                         // just comment out the line below...
2391                         showCursor();
2392                 } else {
2393                         bv_->cut(false);
2394                 }
2395                 moveCursorUpdate(false);
2396                 owner_->showState();
2397                 setState();
2398         }
2399         break;
2400
2401         case LFUN_DELETE_SKIP:
2402         {
2403                 LyXText * lt = bv_->getLyXText();
2404
2405                 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
2406                 
2407                 LyXCursor cursor = lt->cursor;
2408
2409                 if (!lt->selection.set()) {
2410                         if (cursor.pos() == cursor.par()->size()) {
2411                                 lt->cursorRight(bv_);
2412                                 cursor = lt->cursor;
2413                                 if (cursor.pos() == 0
2414                                     && !(cursor.par()->params().spaceTop()
2415                                          == VSpace (VSpace::NONE))) {
2416                                         lt->setParagraph
2417                                                 (bv_,
2418                                                  cursor.par()->params().lineTop(),
2419                                                  cursor.par()->params().lineBottom(),
2420                                                  cursor.par()->params().pagebreakTop(), 
2421                                                  cursor.par()->params().pagebreakBottom(),
2422                                                  VSpace(VSpace::NONE), 
2423                                                  cursor.par()->params().spaceBottom(),
2424                                                  cursor.par()->params().spacing(), 
2425                                                  cursor.par()->params().align(), 
2426                                                  cursor.par()->params().labelWidthString(), 0);
2427                                         lt->cursorLeft(bv_);
2428                                         update(lt, 
2429                                                BufferView::SELECT
2430                                                | BufferView::FITCUR
2431                                                | BufferView::CHANGE);
2432                                 } else {
2433                                         lt->cursorLeft(bv_);
2434                                         lt->Delete(bv_);
2435                                         lt->selection.cursor = lt->cursor;
2436                                         update(lt,
2437                                                BufferView::SELECT
2438                                                | BufferView::FITCUR
2439                                                | BufferView::CHANGE);
2440                                 }
2441                         } else {
2442                                 lt->Delete(bv_);
2443                                 lt->selection.cursor = lt->cursor;
2444                                 update(lt,
2445                                        BufferView::SELECT
2446                                        | BufferView::FITCUR
2447                                        | BufferView::CHANGE);
2448                         }
2449                 } else {
2450                         bv_->cut(false);
2451                 }
2452         }
2453         break;
2454
2455         /* -------> Delete word forward. */
2456         case LFUN_DELETE_WORD_FORWARD:
2457                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
2458                 bv_->getLyXText()->deleteWordForward(bv_);
2459                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2460                 moveCursorUpdate(false);
2461                 owner_->showState();
2462                 break;
2463
2464                 /* -------> Delete word backward. */
2465         case LFUN_DELETE_WORD_BACKWARD:
2466         {
2467                 LyXText * lt = bv_->getLyXText();
2468                 
2469                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2470                 lt->deleteWordBackward(bv_);
2471                 update(lt,
2472                        BufferView::SELECT
2473                        | BufferView::FITCUR
2474                        | BufferView::CHANGE);
2475                 moveCursorUpdate(false);
2476                 owner_->showState();
2477         }
2478         break;
2479                 
2480                 /* -------> Kill to end of line. */
2481         case LFUN_DELETE_LINE_FORWARD:
2482         {
2483                 LyXText * lt = bv_->getLyXText();
2484                 
2485                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2486                 lt->deleteLineForward(bv_);
2487                 update(lt,
2488                        BufferView::SELECT
2489                        | BufferView::FITCUR
2490                        | BufferView::CHANGE);
2491                 moveCursorUpdate(false);
2492         }
2493         break;
2494                 
2495                 /* -------> Set mark off. */
2496         case LFUN_MARK_OFF:
2497         {
2498                 LyXText * lt = bv_->getLyXText();
2499                 
2500                 beforeChange(lt);
2501                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2502                 lt->selection.cursor = lt->cursor;
2503                 owner_->getLyXFunc()->setMessage(N_("Mark off"));
2504         }
2505         break;
2506
2507                 /* -------> Set mark on. */
2508         case LFUN_MARK_ON:
2509         {
2510                 LyXText * lt = bv_->getLyXText();
2511                 
2512                 beforeChange(lt);
2513                 lt->selection.mark(true);
2514                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2515                 lt->selection.cursor = lt->cursor;
2516                 owner_->getLyXFunc()->setMessage(N_("Mark on"));
2517         }
2518         break;
2519                 
2520         case LFUN_BACKSPACE:
2521         {
2522                 LyXText * lt = bv_->getLyXText();
2523                 
2524                 if (!lt->selection.set()) {
2525                         if (owner_->getIntl()->getTrans().backspace()) {
2526                                 lt->backspace(bv_);
2527                                 lt->selection.cursor = lt->cursor;
2528                                 update(lt,
2529                                        BufferView::SELECT
2530                                        | BufferView::FITCUR
2531                                        | BufferView::CHANGE);
2532                                 // It is possible to make it a lot faster still
2533                                 // just comment out the line below...
2534                                 showCursor();
2535                         }
2536                 } else {
2537                         bv_->cut(false);
2538                 }
2539                 owner_->showState();
2540                 setState();
2541         }
2542         break;
2543
2544         case LFUN_BACKSPACE_SKIP:
2545         {
2546                 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
2547                 LyXText * lt = bv_->getLyXText();
2548                 
2549                 LyXCursor cursor = lt->cursor;
2550                 
2551                 if (!lt->selection.set()) {
2552                         if (cursor.pos() == 0 
2553                             && !(cursor.par()->params().spaceTop() 
2554                                  == VSpace (VSpace::NONE))) {
2555                                 lt->setParagraph 
2556                                         (bv_,
2557                                          cursor.par()->params().lineTop(),      
2558                                          cursor.par()->params().lineBottom(),
2559                                          cursor.par()->params().pagebreakTop(), 
2560                                          cursor.par()->params().pagebreakBottom(),
2561                                          VSpace(VSpace::NONE), cursor.par()->params().spaceBottom(),
2562                                          cursor.par()->params().spacing(), 
2563                                          cursor.par()->params().align(), 
2564                                          cursor.par()->params().labelWidthString(), 0);
2565                                 update(lt,
2566                                        BufferView::SELECT
2567                                        | BufferView::FITCUR
2568                                        | BufferView::CHANGE);
2569                         } else {
2570                                 lt->backspace(bv_);
2571                                 lt->selection.cursor = cursor;
2572                                 update(lt,
2573                                        BufferView::SELECT
2574                                        | BufferView::FITCUR
2575                                        | BufferView::CHANGE);
2576                         }
2577                 } else
2578                         bv_->cut(false);
2579         }
2580         break;
2581
2582         case LFUN_BREAKPARAGRAPH:
2583         {
2584                 LyXText * lt = bv_->getLyXText();
2585                 
2586                 beforeChange(lt);
2587                 lt->breakParagraph(bv_, 0);
2588                 update(lt,
2589                        BufferView::SELECT
2590                        | BufferView::FITCUR
2591                        | BufferView::CHANGE);
2592                 lt->selection.cursor = lt->cursor;
2593                 setState();
2594                 owner_->showState();
2595                 break;
2596         }
2597
2598         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
2599         {
2600                 LyXText * lt = bv_->getLyXText();
2601                 
2602                 beforeChange(lt);
2603                 lt->breakParagraph(bv_, 1);
2604                 update(lt,
2605                        BufferView::SELECT
2606                        | BufferView::FITCUR
2607                        | BufferView::CHANGE);
2608                 lt->selection.cursor = lt->cursor;
2609                 setState();
2610                 owner_->showState();
2611                 break;
2612         }
2613         
2614         case LFUN_BREAKPARAGRAPH_SKIP:
2615         {
2616                 // When at the beginning of a paragraph, remove
2617                 // indentation and add a "defskip" at the top.
2618                 // Otherwise, do the same as LFUN_BREAKPARAGRAPH.
2619                 LyXText * lt = bv_->getLyXText();
2620                 
2621                 LyXCursor cursor = lt->cursor;
2622                 
2623                 beforeChange(lt);
2624                 if (cursor.pos() == 0) {
2625                         if (cursor.par()->params().spaceTop() == VSpace(VSpace::NONE)) {
2626                                 lt->setParagraph
2627                                         (bv_,
2628                                          cursor.par()->params().lineTop(),
2629                                          cursor.par()->params().lineBottom(),
2630                                          cursor.par()->params().pagebreakTop(),
2631                                          cursor.par()->params().pagebreakBottom(),
2632                                          VSpace(VSpace::DEFSKIP), cursor.par()->params().spaceBottom(),
2633                                          cursor.par()->params().spacing(),
2634                                          cursor.par()->params().align(),
2635                                          cursor.par()->params().labelWidthString(), 1);
2636                                 //update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2637                         } 
2638                 }
2639                 else {
2640                         lt->breakParagraph(bv_, 0);
2641                         //update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2642                 }
2643
2644                 update(lt,
2645                        BufferView::SELECT
2646                        | BufferView::FITCUR
2647                        | BufferView::CHANGE);
2648                 lt->selection.cursor = cursor;
2649                 setState();
2650                 owner_->showState();
2651         }
2652         break;
2653
2654         case LFUN_PARAGRAPH_SPACING:
2655         {
2656                 LyXText * lt = bv_->getLyXText();
2657                 
2658                 Paragraph * par = lt->cursor.par();
2659                 Spacing::Space cur_spacing = par->params().spacing().getSpace();
2660                 float cur_value = 1.0;
2661                 if (cur_spacing == Spacing::Other) {
2662                         cur_value = par->params().spacing().getValue();
2663                 }
2664                 
2665                 istringstream istr(argument.c_str());
2666
2667                 string tmp;
2668                 istr >> tmp;
2669                 Spacing::Space new_spacing = cur_spacing;
2670                 float new_value = cur_value;
2671                 if (tmp.empty()) {
2672                         lyxerr << "Missing argument to `paragraph-spacing'"
2673                                << endl;
2674                 } else if (tmp == "single") {
2675                         new_spacing = Spacing::Single;
2676                 } else if (tmp == "onehalf") {
2677                         new_spacing = Spacing::Onehalf;
2678                 } else if (tmp == "double") {
2679                         new_spacing = Spacing::Double;
2680                 } else if (tmp == "other") {
2681                         new_spacing = Spacing::Other;
2682                         float tmpval = 0.0;
2683                         istr >> tmpval;
2684                         lyxerr << "new_value = " << tmpval << endl;
2685                         if (tmpval != 0.0)
2686                                 new_value = tmpval;
2687                 } else if (tmp == "default") {
2688                         new_spacing = Spacing::Default;
2689                 } else {
2690                         lyxerr << _("Unknown spacing argument: ")
2691                                << argument << endl;
2692                 }
2693                 if (cur_spacing != new_spacing || cur_value != new_value) {
2694                         par->params().spacing(Spacing(new_spacing, new_value));
2695                         lt->redoParagraph(bv_);
2696                         update(lt,
2697                                BufferView::SELECT
2698                                | BufferView::FITCUR
2699                                | BufferView::CHANGE);
2700                 }
2701         }
2702         break;
2703         
2704         case LFUN_INSET_TOGGLE:
2705         {
2706                 LyXText * lt = bv_->getLyXText();
2707                 hideCursor();
2708                 beforeChange(lt);
2709                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2710                 lt->toggleInset(bv_);
2711                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2712                 setState();
2713         }       
2714                 break;
2715
2716         case LFUN_QUOTE:
2717                 smartQuote();
2718                 break;
2719
2720         case LFUN_HTMLURL:
2721         case LFUN_URL:
2722         {
2723                 InsetCommandParams p;
2724                 if (action == LFUN_HTMLURL)
2725                         p.setCmdName("htmlurl");
2726                 else
2727                         p.setCmdName("url");
2728                 owner_->getDialogs()->createUrl(p.getAsString());
2729         }
2730         break;
2731         
2732         case LFUN_INSERT_URL:
2733         {
2734                 InsetCommandParams p;
2735                 p.setFromString(argument);
2736
2737                 InsetUrl * inset = new InsetUrl(p);
2738                 if (!insertInset(inset))
2739                         delete inset;
2740                 else
2741                         updateInset(inset, true);
2742         }
2743         break;
2744         
2745         case LFUN_INSET_TEXT:
2746                 insertAndEditInset(new InsetText);
2747                 break;
2748         
2749         case LFUN_INSET_ERT:
2750                 insertAndEditInset(new InsetERT);
2751                 break;
2752         
2753         case LFUN_INSET_EXTERNAL:
2754                 insertAndEditInset(new InsetExternal);
2755                 break;
2756         
2757         case LFUN_INSET_FOOTNOTE:
2758                 insertAndEditInset(new InsetFoot);
2759                 break;
2760
2761         case LFUN_INSET_MARGINAL:
2762                 insertAndEditInset(new InsetMarginal);
2763                 break;
2764
2765         case LFUN_INSET_MINIPAGE:
2766                 insertAndEditInset(new InsetMinipage);
2767                 break;
2768
2769         case LFUN_INSERT_NOTE:
2770                 insertAndEditInset(new InsetNote);
2771                 break;
2772
2773         case LFUN_INSET_FLOAT:
2774                 // check if the float type exist
2775                 if (floatList.typeExist(argument)) {
2776                         insertAndEditInset(new InsetFloat(argument));
2777                 } else {
2778                         lyxerr << "Non-existent float type: "
2779                                << argument << endl;
2780                 }
2781                 break;
2782
2783         case LFUN_INSET_WIDE_FLOAT:
2784         {
2785                 // check if the float type exist
2786                 if (floatList.typeExist(argument)) {
2787                         InsetFloat * new_inset = new InsetFloat(argument);
2788                         new_inset->wide(true);
2789                         if (insertInset(new_inset))
2790                                 new_inset->edit(bv_);
2791                         else
2792                                 delete new_inset;
2793                 } else {
2794                         lyxerr << "Non-existent float type: "
2795                                << argument << endl;
2796                 }
2797                 
2798         }
2799         break;
2800
2801 #if 0
2802         case LFUN_INSET_LIST:
2803                 insertAndEditInset(new InsetList);
2804                 break;
2805
2806         case LFUN_INSET_THEOREM:
2807                 insertAndEditInset(new InsetTheorem);
2808                 break;
2809 #endif
2810                 
2811         case LFUN_INSET_CAPTION:
2812         {
2813                 // Do we have a locking inset...
2814                 if (bv_->theLockingInset()) {
2815                         lyxerr << "Locking inset code: "
2816                                << static_cast<int>(bv_->theLockingInset()->lyxCode());
2817                         InsetCaption * new_inset = new InsetCaption;
2818                         new_inset->setOwner(bv_->theLockingInset());
2819                         new_inset->setAutoBreakRows(true);
2820                         new_inset->setDrawFrame(0, InsetText::LOCKED);
2821                         new_inset->setFrameColor(0, LColor::captionframe);
2822                         if (insertInset(new_inset))
2823                                 new_inset->edit(bv_);
2824                         else
2825                                 delete new_inset;
2826                 }
2827         }
2828         break;
2829         
2830         case LFUN_INSET_TABULAR:
2831         {
2832                 int r = 2;
2833                 int c = 2;
2834                 if (!argument.empty())
2835                         ::sscanf(argument.c_str(),"%d%d", &r, &c);
2836                 InsetTabular * new_inset =
2837                         new InsetTabular(*buffer_, r, c);
2838                 bool const rtl =
2839                         bv_->getLyXText()->real_current_font.isRightToLeft();
2840                 if (!open_new_inset(new_inset, rtl))
2841                         delete new_inset;
2842         }
2843         break;
2844
2845         // --- lyxserver commands ----------------------------
2846
2847         case LFUN_CHARATCURSOR:
2848         {
2849                 pos_type pos = bv_->getLyXText()->cursor.pos();
2850                 if (pos < bv_->getLyXText()->cursor.par()->size())
2851                         owner_->getLyXFunc()->setMessage(
2852                                 tostr(bv_->getLyXText()->cursor.par()->getChar(pos)));
2853                 else
2854                         owner_->getLyXFunc()->setMessage("EOF");
2855         }
2856         break;
2857         
2858         case LFUN_GETXY:
2859                 owner_->getLyXFunc()->setMessage(tostr(bv_->getLyXText()->cursor.x())
2860                                                  + ' '
2861                                                  + tostr(bv_->getLyXText()->cursor.y()));
2862                 break;
2863                 
2864         case LFUN_SETXY:
2865         {
2866                 int x = 0;
2867                 int y = 0;
2868                 if (::sscanf(argument.c_str(), " %d %d", &x, &y) != 2) {
2869                         lyxerr << "SETXY: Could not parse coordinates in '"
2870                                << argument << std::endl;
2871                 }
2872                 bv_->getLyXText()->setCursorFromCoordinates(bv_, x, y);
2873         }
2874         break;
2875         
2876         case LFUN_GETLAYOUT:
2877                 owner_->getLyXFunc()->setMessage(tostr(bv_->getLyXText()->cursor.par()->layout()));
2878                 break;
2879                         
2880         case LFUN_GETFONT:
2881         {
2882                 LyXFont & font = bv_->getLyXText()->current_font;
2883                 if (font.shape() == LyXFont::ITALIC_SHAPE)
2884                         owner_->getLyXFunc()->setMessage("E");
2885                 else if (font.shape() == LyXFont::SMALLCAPS_SHAPE)
2886                         owner_->getLyXFunc()->setMessage("N");
2887                 else
2888                         owner_->getLyXFunc()->setMessage("0");
2889
2890         }
2891         break;
2892
2893         // --- accented characters ---------------------------
2894                 
2895         case LFUN_UMLAUT:
2896         case LFUN_CIRCUMFLEX:
2897         case LFUN_GRAVE:
2898         case LFUN_ACUTE:
2899         case LFUN_TILDE:
2900         case LFUN_CEDILLA:
2901         case LFUN_MACRON:
2902         case LFUN_DOT:
2903         case LFUN_UNDERDOT:
2904         case LFUN_UNDERBAR:
2905         case LFUN_CARON:
2906         case LFUN_SPECIAL_CARON:
2907         case LFUN_BREVE:
2908         case LFUN_TIE:
2909         case LFUN_HUNG_UMLAUT:
2910         case LFUN_CIRCLE:
2911         case LFUN_OGONEK:
2912                 if (argument.empty()) {
2913                         // As always...
2914                         owner_->getLyXFunc()->handleKeyFunc(action);
2915                 } else {
2916                         owner_->getLyXFunc()->handleKeyFunc(action);
2917                         owner_->getIntl()->getTrans()
2918                                 .TranslateAndInsert(argument[0], bv_->getLyXText());
2919                         update(bv_->getLyXText(),
2920                                BufferView::SELECT
2921                                | BufferView::FITCUR
2922                                | BufferView::CHANGE);
2923                 }
2924                 break;
2925         
2926         case LFUN_MATH_MACRO:
2927                 mathDispatchMathMacro(bv_, argument);
2928                 break;
2929
2930         case LFUN_MATH_DELIM:     
2931                 mathDispatchMathDelim(bv_, argument);
2932                 break;
2933
2934         case LFUN_INSERT_MATRIX:
2935                 mathDispatchInsertMatrix(bv_, argument);
2936                 break;
2937
2938         case LFUN_INSERT_MATH:
2939                 mathDispatchInsertMath(bv_, argument);
2940                 break;
2941
2942         case LFUN_MATH_IMPORT_SELECTION: // Imports LaTeX from the X selection
2943                 mathDispatchMathImportSelection(bv_, argument);
2944                 break;
2945
2946         case LFUN_MATH_DISPLAY:          // Open or create a displayed math inset
2947                 mathDispatchMathDisplay(bv_, argument);
2948                 break;
2949
2950         case LFUN_MATH_MODE:             // Open or create an inlined math inset 
2951                 mathDispatchMathMode(bv_, argument);
2952                 break;
2953                 
2954         case LFUN_GREEK:                 // Insert a single greek letter
2955                 mathDispatchGreek(bv_, argument);
2956                 break;
2957                 
2958         case LFUN_CITATION_INSERT:
2959         {
2960                 InsetCommandParams p;
2961                 p.setFromString(argument);
2962
2963                 InsetCitation * inset = new InsetCitation(p);
2964                 if (!insertInset(inset))
2965                         delete inset;
2966                 else
2967                         updateInset(inset, true);
2968         }
2969         break;
2970                     
2971         case LFUN_INSERT_BIBTEX:
2972         {   
2973                 // ale970405+lasgoutt970425
2974                 // The argument can be up to two tokens separated 
2975                 // by a space. The first one is the bibstyle.
2976                 string const db       = token(argument, ' ', 0);
2977                 string const bibstyle = token(argument, ' ', 1);
2978
2979                 InsetCommandParams p("BibTeX", db, bibstyle);
2980                 InsetBibtex * inset = new InsetBibtex(p);
2981                 
2982                 if (insertInset(inset)) {
2983                         if (argument.empty())
2984                                 inset->edit(bv_);
2985                 } else
2986                         delete inset;
2987         }
2988         break;
2989                 
2990         // BibTeX data bases
2991         case LFUN_BIBDB_ADD:
2992         {
2993                 InsetBibtex * inset = 
2994                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
2995                 if (inset) {
2996                         inset->addDatabase(argument);
2997                 }
2998         }
2999         break;
3000                     
3001         case LFUN_BIBDB_DEL:
3002         {
3003                 InsetBibtex * inset = 
3004                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
3005                 if (inset) {
3006                         inset->delDatabase(argument);
3007                 }
3008         }
3009         break;
3010         
3011         case LFUN_BIBTEX_STYLE:
3012         {
3013                 InsetBibtex * inset = 
3014                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
3015                 if (inset) {
3016                         inset->setOptions(argument);
3017                 }
3018         }
3019         break;
3020                 
3021         case LFUN_INDEX_CREATE:
3022         {
3023                 InsetCommandParams p("index");
3024                 if (argument.empty()) {
3025                         string const idxstring(bv_->getLyXText()->getStringToIndex(bv_));
3026                         p.setContents(idxstring);
3027                 } else {
3028                         p.setContents(argument);
3029                 }
3030
3031                 owner_->getDialogs()->createIndex(p.getAsString());
3032         }
3033         break;
3034                     
3035         case LFUN_INDEX_INSERT:
3036         {
3037                 InsetCommandParams p;
3038                 p.setFromString(argument);
3039                 InsetIndex * inset = new InsetIndex(p);
3040
3041                 if (!insertInset(inset))
3042                         delete inset;
3043                 else
3044                         updateInset(inset, true);
3045         }
3046         break;
3047                     
3048         case LFUN_INDEX_INSERT_LAST:
3049         {
3050                 string const idxstring(bv_->getLyXText()->getStringToIndex(bv_));
3051                 if (!idxstring.empty()) {
3052                         owner_->message(_("Word `")
3053                                         + idxstring + _(("' indexed.")));
3054                         InsetCommandParams p("index", idxstring);
3055                         InsetIndex * inset = new InsetIndex(p);
3056                         
3057                         if (!insertInset(inset))
3058                                 delete inset;
3059                         else
3060                                 updateInset(inset, true);
3061                 }
3062         }
3063         break;
3064
3065         case LFUN_INDEX_PRINT:
3066         {
3067                 InsetCommandParams p("printindex");
3068                 Inset * inset = new InsetPrintIndex(p);
3069                 if (!insertInset(inset, "Standard"))
3070                         delete inset;
3071         }
3072         break;
3073
3074         case LFUN_PARENTINSERT:
3075         {
3076                 lyxerr << "arg " << argument << endl;
3077                 InsetCommandParams p("lyxparent", argument);
3078                 Inset * inset = new InsetParent(p, *buffer_);
3079                 if (!insertInset(inset, "Standard"))
3080                         delete inset;
3081         }
3082                  
3083         break;
3084
3085         case LFUN_CHILD_INSERT:
3086         {
3087                 InsetInclude::Params p;
3088                 p.cparams.setFromString(argument);
3089                 p.masterFilename_ = buffer_->fileName();
3090
3091                 InsetInclude * inset = new InsetInclude(p);
3092                 if (!insertInset(inset))
3093                         delete inset;
3094                 else {
3095                         updateInset(inset, true);
3096                         bv_->owner()->getDialogs()->showInclude(inset);
3097                 }
3098         }
3099         break; 
3100
3101         case LFUN_FLOAT_LIST:
3102         {
3103                 // We should check the argument for validity. (Lgb)
3104                 Inset * inset = new InsetFloatList(argument);
3105                 if (!insertInset(inset, "Standard"))
3106                         delete inset;
3107         }
3108         break;
3109         
3110         case LFUN_THESAURUS_ENTRY:
3111         {
3112                 string arg = argument;
3113
3114                 if (arg.empty()) {
3115                         arg = bv_->getLyXText()->selectionAsString(buffer_,
3116                                                                    false);
3117  
3118                         // FIXME
3119                         if (arg.size() > 100 || arg.empty()) {
3120                                 // Get word or selection
3121                                 bv_->getLyXText()->selectWordWhenUnderCursor(bv_, LyXText::WHOLE_WORD);
3122                                 arg = bv_->getLyXText()->selectionAsString(buffer_, false);
3123                                 // FIXME: where is getLyXText()->unselect(bv_) ?
3124                         }
3125                 }
3126
3127                 bv_->owner()->getDialogs()->showThesaurus(arg);
3128         }
3129                 break;
3130  
3131         case LFUN_SELFINSERT:
3132         {
3133                 if (argument.empty()) break;
3134                 
3135                 /* Automatically delete the currently selected
3136                  * text and replace it with what is being
3137                  * typed in now. Depends on lyxrc settings
3138                  * "auto_region_delete", which defaults to
3139                  * true (on). */
3140
3141                 LyXText * lt = bv_->getLyXText();
3142                 
3143                 if (lyxrc.auto_region_delete) {
3144                         if (lt->selection.set()) {
3145                                 lt->cutSelection(bv_, false, false);
3146                                 bv_->update(lt,
3147                                             BufferView::SELECT
3148                                             | BufferView::FITCUR
3149                                             | BufferView::CHANGE);
3150                         }
3151                 }
3152                 
3153                 beforeChange(lt);
3154                 LyXFont const old_font(lt->real_current_font);
3155                 
3156                 string::const_iterator cit = argument.begin();
3157                 string::const_iterator end = argument.end();
3158                 for (; cit != end; ++cit) {
3159                         owner_->getIntl()->getTrans().TranslateAndInsert(*cit, lt);
3160                 }
3161                 
3162                 bv_->update(lt,
3163                             BufferView::SELECT
3164                             | BufferView::FITCUR
3165                             | BufferView::CHANGE);
3166                 
3167                 lt->selection.cursor = lt->cursor;
3168                 moveCursorUpdate(false);
3169                 
3170                 // real_current_font.number can change so we need to
3171                 // update the minibuffer
3172                 if (old_font != lt->real_current_font)
3173                         owner_->showState();
3174                 //return string();
3175         }
3176         break;
3177
3178         case LFUN_DATE_INSERT:  // jdblair: date-insert cmd
3179         {
3180                 time_t now_time_t = time(NULL);
3181                 struct tm * now_tm = localtime(&now_time_t);
3182                 setlocale(LC_TIME, "");
3183                 string arg;
3184                 if (!argument.empty())
3185                         arg = argument;
3186                 else 
3187                         arg = lyxrc.date_insert_format;
3188                 char datetmp[32];
3189                 int const datetmp_len =
3190                         ::strftime(datetmp, 32, arg.c_str(), now_tm);
3191
3192                 LyXText * lt = bv_->getLyXText();
3193                 
3194                 for (int i = 0; i < datetmp_len; i++) {
3195                         lt->insertChar(bv_, datetmp[i]);
3196                         update(lt,
3197                                BufferView::SELECT
3198                                | BufferView::FITCUR
3199                                | BufferView::CHANGE);
3200                 }
3201
3202                 lt->selection.cursor = lt->cursor;
3203                 moveCursorUpdate(false);
3204         }
3205         break;
3206
3207         case LFUN_UNKNOWN_ACTION:
3208                 owner_->getLyXFunc()->setErrorMessage(N_("Unknown function!"));
3209                 break;
3210         
3211         default:
3212                 return false;
3213         } // end of switch
3214
3215         return true;
3216 }
3217
3218
3219 void BufferView::Pimpl::newline()
3220 {
3221         if (available()) {
3222                 LyXText * lt = bv_->getLyXText();
3223                 hideCursor();
3224                 update(lt,
3225                        BufferView::SELECT
3226                        | BufferView::FITCUR);
3227                 lt->insertChar(bv_, Paragraph::META_NEWLINE);
3228                 update(lt,
3229                        BufferView::SELECT
3230                        | BufferView::FITCUR
3231                        | BufferView::CHANGE);
3232         }
3233 }
3234
3235
3236 void BufferView::Pimpl::hfill()
3237 {
3238         if (available()) {
3239                 LyXText * lt = bv_->getLyXText();
3240                 hideCursor();
3241                 update(lt,
3242                        BufferView::SELECT
3243                        | BufferView::FITCUR);
3244                 lt->insertChar(bv_, Paragraph::META_HFILL);
3245                 update(lt,
3246                        BufferView::SELECT
3247                        | BufferView::FITCUR
3248                        | BufferView::CHANGE);
3249         }
3250 }
3251
3252
3253 void BufferView::Pimpl::protectedBlank(LyXText * lt)
3254 {
3255         if (available()) {
3256                 hideCursor();
3257                 update(lt, BufferView::SELECT|BufferView::FITCUR);
3258                 InsetSpecialChar * new_inset =
3259                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
3260 #ifdef WITH_WARNINGS
3261 #warning Why is this code different from specialChar() below? (JMarc)
3262 // the code in specialChar is a generic version of what used to exist
3263 // for other special chars. I did not merge this case because of the
3264 // call to updateInset(), but what does it do?
3265 #endif
3266                 if (!insertInset(new_inset))
3267                         delete new_inset;
3268                 else
3269                         updateInset(new_inset, true);
3270         }
3271 }
3272
3273
3274 void BufferView::Pimpl::specialChar(InsetSpecialChar::Kind kind)
3275 {
3276         if (available()) {
3277                 LyXText * lt = bv_->getLyXText();
3278                 
3279                 hideCursor();
3280                 update(lt, BufferView::SELECT|BufferView::FITCUR);
3281                 InsetSpecialChar * new_inset = 
3282                         new InsetSpecialChar(kind);
3283                 if (!insertInset(new_inset))
3284                         delete new_inset;
3285         }
3286 }
3287
3288
3289 void BufferView::Pimpl::smartQuote()
3290 {
3291         LyXText const * lt = bv_->getLyXText();
3292         Paragraph const * par = lt->cursor.par();
3293         pos_type pos = lt->cursor.pos();
3294         char c;
3295
3296         if (!pos
3297             || (par->isInset(pos - 1)
3298                 && par->getInset(pos - 1)->isSpace()))
3299                 c = ' ';
3300         else
3301                 c = par->getChar(pos - 1);
3302                 
3303
3304         hideCursor();
3305
3306         LyXLayout const & style =
3307                 textclasslist[bv_->buffer()->params.textclass][par->layout()];
3308         
3309         if (style.pass_thru ||
3310                 (!insertInset(new InsetQuotes(c, bv_->buffer()->params))))
3311                 bv_->owner()->getLyXFunc()->dispatch(LFUN_SELFINSERT, "\"");
3312 }
3313
3314
3315 void BufferView::Pimpl::insertAndEditInset(Inset * inset)
3316 {
3317         if (insertInset(inset))
3318                 inset->edit(bv_);
3319         else
3320                 delete inset;
3321 }
3322
3323  
3324 // Open and lock an updatable inset
3325 bool BufferView::Pimpl::open_new_inset(UpdatableInset * new_inset, bool behind)
3326 {
3327         LyXText * lt = bv_->getLyXText();
3328         
3329         beforeChange(lt);
3330         finishUndo();
3331         if (!insertInset(new_inset)) {
3332                 delete new_inset;
3333                 return false;
3334         }
3335         new_inset->edit(bv_, !behind);
3336         return true;
3337 }
3338
3339
3340 bool BufferView::Pimpl::insertInset(Inset * inset, string const & lout)
3341 {
3342         // if we are in a locking inset we should try to insert the
3343         // inset there otherwise this is a illegal function now
3344         if (bv_->theLockingInset()) {
3345                 if (bv_->theLockingInset()->insetAllowed(inset))
3346                     return bv_->theLockingInset()->insertInset(bv_, inset);
3347                 return false;
3348         }
3349
3350         // not quite sure if we want this...
3351         setCursorParUndo(bv_);
3352         freezeUndo();
3353         
3354         beforeChange(bv_->text);
3355         if (!lout.empty()) {
3356                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3357                 bv_->text->breakParagraph(bv_);
3358                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3359
3360                 if (bv_->text->cursor.par()->size()) {
3361                         bv_->text->cursorLeft(bv_);
3362                         
3363                         bv_->text->breakParagraph(bv_);
3364                         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3365                 }
3366
3367                 string lres = lout;
3368                 LyXTextClass const & tclass =
3369                         textclasslist[buffer_->params.textclass];
3370                 bool hasLayout = tclass.hasLayout(lres);
3371                 string lay = tclass.defaultLayoutName();
3372
3373                 if (hasLayout != false) {
3374                         // layout found
3375                         lay = lres;
3376                 } else {
3377                         // layout not fount using default
3378                         lay = tclass.defaultLayoutName();
3379                 }
3380
3381                 bv_->text->setLayout(bv_, lay);
3382                 
3383                 bv_->text->setParagraph(bv_, 0, 0,
3384                                    0, 0,
3385                                    VSpace(VSpace::NONE), VSpace(VSpace::NONE),
3386                                    Spacing(),
3387                                    LYX_ALIGN_LAYOUT, 
3388                                    string(),
3389                                    0);
3390                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3391         }
3392         
3393         bv_->text->insertInset(bv_, inset);
3394         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3395
3396         unFreezeUndo();
3397         return true;
3398 }
3399
3400
3401 void BufferView::Pimpl::updateInset(Inset * inset, bool mark_dirty)
3402 {
3403         if (!inset)
3404                 return;
3405
3406         // first check for locking insets
3407         if (bv_->theLockingInset()) {
3408                 if (bv_->theLockingInset() == inset) {
3409                         if (bv_->text->updateInset(bv_, inset)) {
3410                                 update();
3411                                 if (mark_dirty) {
3412                                         buffer_->markDirty();
3413                                 }
3414                                 updateScrollbar();
3415                                 return;
3416                         }
3417                 } else if (bv_->theLockingInset()->updateInsetInInset(bv_, inset)) {
3418                         if (bv_->text->updateInset(bv_,  bv_->theLockingInset())) {
3419                                 update();
3420                                 if (mark_dirty) {
3421                                         buffer_->markDirty();
3422                                 }
3423                                 updateScrollbar();
3424                                 return;
3425                         }
3426                 }
3427         }
3428   
3429         // then check the current buffer
3430         if (available()) {
3431                 hideCursor();
3432                 update(bv_->text, BufferView::UPDATE);
3433                 if (bv_->text->updateInset(bv_, inset)) {
3434                         if (mark_dirty) {
3435                                 update(bv_->text,
3436                                        BufferView::SELECT
3437                                        | BufferView::FITCUR
3438                                        | BufferView::CHANGE);
3439                         } else {
3440                                 update(bv_->text, SELECT);
3441                         }
3442                         return;
3443                 }
3444         }
3445 }
3446
3447
3448 void BufferView::Pimpl::gotoInset(vector<Inset::Code> const & codes,
3449                                   bool same_content)
3450 {
3451         if (!available()) return;
3452         
3453         hideCursor();
3454         beforeChange(bv_->text);
3455         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3456         
3457         LyXCursor const & cursor = bv_->text->cursor;
3458  
3459         string contents;
3460         if (same_content &&
3461             cursor.par()->isInset(cursor.pos())) {
3462                 Inset const * inset = cursor.par()->getInset(cursor.pos());
3463                 if (find(codes.begin(), codes.end(), inset->lyxCode())
3464                     != codes.end())
3465                         contents =
3466                                 static_cast<InsetCommand const *>(inset)->getContents();
3467         }
3468         
3469  
3470         if (!bv_->text->gotoNextInset(bv_, codes, contents)) {
3471                 if (bv_->text->cursor.pos() 
3472                     || bv_->text->cursor.par() != bv_->text->ownerParagraph()) {
3473                         LyXCursor tmp = bv_->text->cursor;
3474                         bv_->text->cursor.par(bv_->text->ownerParagraph());
3475                         bv_->text->cursor.pos(0);
3476                         if (!bv_->text->gotoNextInset(bv_, codes, contents)) {
3477                                 bv_->text->cursor = tmp;
3478                                 bv_->owner()->message(_("No more insets"));
3479                         }
3480                 } else {
3481                         bv_->owner()->message(_("No more insets"));
3482                 }
3483         }
3484         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3485         bv_->text->selection.cursor = bv_->text->cursor;
3486 }
3487
3488
3489 void BufferView::Pimpl::gotoInset(Inset::Code code, bool same_content)
3490 {
3491         gotoInset(vector<Inset::Code>(1, code), same_content);
3492 }