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