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