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