]> git.lyx.org Git - lyx.git/blob - src/BufferView_pimpl.C
lyxstring compile fixes ; small stuff
[lyx.git] / src / BufferView_pimpl.C
1 #include <config.h>
2
3 #include <ctime>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 #include <locale.h>
7
8 #ifdef __GNUG__
9 #pragma implementation
10 #endif
11
12 #include "BufferView_pimpl.h"
13 #include "WorkArea.h"
14 #include "lyxscreen.h"
15 #include "lyxtext.h"
16 #include "lyxrow.h"
17 #include "LyXView.h"
18 #include "commandtags.h"
19 #include "lyxfunc.h"
20 #include "font.h"
21 #include "bufferview_funcs.h"
22 #include "TextCache.h"
23 #include "bufferlist.h"
24 #include "lyx_gui_misc.h"
25 #include "lyxrc.h"
26 #include "intl.h"
27 #include "support/LAssert.h"
28 #include "frontends/Dialogs.h"
29 #include "insets/insetbib.h"
30 #include "insets/insettext.h"
31 /// added for Dispatch functions
32 #include "lyx_cb.h"
33 #include "frontends/FileDialog.h"
34 #include "lyx_main.h"
35 #include "FloatList.h"
36 #include "support/filetools.h"
37 #include "support/lyxfunctional.h"
38 #include "insets/inseturl.h"
39 #include "insets/insetlatexaccent.h"
40 #include "insets/insettoc.h"
41 #include "insets/insetref.h"
42 #include "insets/insetparent.h"
43 #include "insets/insetindex.h"
44 #include "insets/insetinfo.h"
45 #include "insets/insetinclude.h"
46 #include "insets/insetcite.h"
47 #include "insets/insetert.h"
48 #include "insets/insetexternal.h"
49 #include "insets/insetgraphics.h"
50 #include "insets/insetfoot.h"
51 #include "insets/insetmarginal.h"
52 #include "insets/insetminipage.h"
53 #include "insets/insetfloat.h"
54 #include "insets/insetlist.h"
55 #include "insets/insettabular.h"
56 #include "insets/insettheorem.h"
57 #include "insets/insetcaption.h"
58 #include "insets/insetfloatlist.h"
59 #include "insets/insetspecialchar.h"
60 #include "mathed/formulamacro.h"
61 #include "mathed/formula.h"
62 #include "gettext.h"
63 #include "ParagraphParameters.h"
64
65 extern LyXTextClass::size_type current_layout;
66 extern int greek_kb_flag;
67
68 using std::vector;
69 using std::find_if;
70 using std::find;
71 using std::pair;
72 using std::endl;
73 using std::make_pair;
74 using std::min;
75 using SigC::slot;
76
77 /* the selection possible is needed, that only motion events are 
78  * used, where the bottom press event was on the drawing area too */
79 bool selection_possible = false;
80
81 extern BufferList bufferlist;
82 extern char ascii_type;
83
84 extern bool math_insert_greek(BufferView *, char);
85 extern void sigchldhandler(pid_t pid, int * status);
86 extern int bibitemMaxWidth(BufferView *, LyXFont const &);
87
88 namespace {
89
90 const unsigned int saved_positions_num = 20;
91
92 inline
93 void waitForX()
94 {
95         XSync(fl_get_display(), 0);
96 }
97
98
99 void SetXtermCursor(Window win)
100 {
101         static Cursor cursor;
102         static bool cursor_undefined = true;
103         if (cursor_undefined){
104                 cursor = XCreateFontCursor(fl_get_display(), XC_xterm);
105                 XFlush(fl_get_display());
106                 cursor_undefined = false;
107         }
108         XDefineCursor(fl_get_display(), win, cursor);
109         XFlush(fl_get_display());
110 }
111
112 } // anon namespace
113
114
115 BufferView::Pimpl::Pimpl(BufferView * b, LyXView * o,
116              int xpos, int ypos, int width, int height)
117         : bv_(b), owner_(o), buffer_(0),
118           current_scrollbar_value(0), cursor_timeout(400),
119           workarea_(xpos, ypos, width, height), using_xterm_cursor(false),
120           inset_slept(false)
121 {
122         // Setup the signals
123         workarea_.scrollCB.connect(slot(this, &BufferView::Pimpl::scrollCB));
124         workarea_.workAreaExpose
125                 .connect(slot(this, &BufferView::Pimpl::workAreaExpose));
126         workarea_.workAreaEnter
127                 .connect(slot(this, &BufferView::Pimpl::enterView));
128         workarea_.workAreaLeave
129                 .connect(slot(this, &BufferView::Pimpl::leaveView));
130         workarea_.workAreaButtonPress
131                 .connect(slot(this, &BufferView::Pimpl::workAreaButtonPress));
132         workarea_.workAreaButtonRelease
133                 .connect(slot(this,
134                               &BufferView::Pimpl::workAreaButtonRelease));
135         workarea_.workAreaMotionNotify
136                 .connect(slot(this, &BufferView::Pimpl::workAreaMotionNotify));
137         workarea_.workAreaDoubleClick
138                 .connect(slot(this, &BufferView::Pimpl::doubleClick));
139         workarea_.workAreaTripleClick
140                 .connect(slot(this, &BufferView::Pimpl::tripleClick));
141         workarea_.workAreaKeyPress
142                 .connect(slot(this, &BufferView::Pimpl::workAreaKeyPress));
143         
144         cursor_timeout.timeout.connect(slot(this,
145                                             &BufferView::Pimpl::cursorToggle));
146         cursor_timeout.start();
147         workarea_.setFocus();
148         saved_positions.resize(saved_positions_num);
149 }
150
151
152 Painter & BufferView::Pimpl::painter() 
153 {
154         return workarea_.getPainter();
155 }
156
157
158 void BufferView::Pimpl::buffer(Buffer * b)
159 {
160         lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
161                             << b << ")" << endl;
162         if (buffer_) {
163                 insetSleep();
164                 buffer_->delUser(bv_);
165
166                 // Put the old text into the TextCache, but
167                 // only if the buffer is still loaded.
168                 // Also set the owner of the test to 0
169                 //              bv_->text->owner(0);
170                 textcache.add(buffer_, workarea_.workWidth(), bv_->text);
171                 if (lyxerr.debugging())
172                         textcache.show(lyxerr, "BufferView::buffer");
173                 
174                 bv_->text = 0;
175         }
176
177         // Set current buffer
178         buffer_ = b;
179
180         if (bufferlist.getState() == BufferList::CLOSING) return;
181         
182         // Nuke old image
183         // screen is always deleted when the buffer is changed.
184         screen_.reset(0);
185
186         // If we are closing the buffer, use the first buffer as current
187         if (!buffer_) {
188                 buffer_ = bufferlist.first();
189         }
190
191         if (buffer_) {
192                 lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl;
193                 buffer_->addUser(bv_);
194                 // If we don't have a text object for this, we make one
195                 if (bv_->text == 0) {
196                         resizeCurrentBuffer();
197                 } else {
198                         updateScreen();
199                         updateScrollbar();
200                 }
201                 bv_->text->first = screen_->TopCursorVisible(bv_->text);
202                 owner_->updateMenubar();
203                 owner_->updateToolbar();
204                 // Similarly, buffer-dependent dialogs should be updated or
205                 // hidden. This should go here because some dialogs (eg ToC)
206                 // require bv_->text.
207                 owner_->getDialogs()->updateBufferDependent(true);
208                 redraw();
209                 insetWakeup();
210         } else {
211                 lyxerr[Debug::INFO] << "  No Buffer!" << endl;
212                 owner_->updateMenubar();
213                 owner_->updateToolbar();
214                 owner_->getDialogs()->hideBufferDependent();
215                 updateScrollbar();
216                 workarea_.redraw();
217
218                 // Also remove all remaining text's from the testcache.
219                 // (there should not be any!) (if there is any it is a
220                 // bug!)
221                 if (lyxerr.debugging())
222                         textcache.show(lyxerr, "buffer delete all");
223                 textcache.clear();
224         }
225         // should update layoutchoice even if we don't have a buffer.
226         owner_->updateLayoutChoice();
227
228         owner_->updateWindowTitle();
229 }
230
231
232 void BufferView::Pimpl::resize(int xpos, int ypos, int width, int height)
233 {
234         workarea_.resize(xpos, ypos, width, height);
235         update(bv_->text, SELECT);
236         redraw();
237 }
238
239
240 void BufferView::Pimpl::resize()
241 {
242         if (buffer_)
243                 resizeCurrentBuffer();
244 }
245
246
247 void BufferView::Pimpl::redraw()
248 {
249         lyxerr[Debug::INFO] << "BufferView::redraw()" << endl;
250         workarea_.redraw();
251 }
252
253
254 bool BufferView::Pimpl::fitCursor(LyXText * text)
255 {
256         lyx::Assert(screen_.get());
257
258         bv_->owner()->getDialogs()->updateParagraph();
259
260         bool const ret = screen_->FitCursor(text, bv_);
261         if (ret)
262             updateScrollbar();
263         return ret;
264 }
265
266
267 void BufferView::Pimpl::redoCurrentBuffer()
268 {
269         lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
270         if (buffer_ && bv_->text) {
271                 resize();
272                 owner_->updateLayoutChoice();
273         }
274 }
275
276
277 int BufferView::Pimpl::resizeCurrentBuffer()
278 {
279         lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
280         
281         Paragraph * par = 0;
282         Paragraph * selstartpar = 0;
283         Paragraph * selendpar = 0;
284         UpdatableInset * the_locking_inset = 0;
285         
286         Paragraph::size_type pos = 0;
287         Paragraph::size_type selstartpos = 0;
288         Paragraph::size_type selendpos = 0;
289         bool selection = false;
290         bool mark_set  = false;
291
292         ProhibitInput(bv_);
293
294         owner_->message(_("Formatting document..."));
295
296         if (bv_->text) {
297                 par = bv_->text->cursor.par();
298                 pos = bv_->text->cursor.pos();
299                 selstartpar = bv_->text->selection.start.par();
300                 selstartpos = bv_->text->selection.start.pos();
301                 selendpar = bv_->text->selection.end.par();
302                 selendpos = bv_->text->selection.end.pos();
303                 selection = bv_->text->selection.set();
304                 mark_set = bv_->text->selection.mark();
305                 the_locking_inset = bv_->theLockingInset();
306                 delete bv_->text;
307                 bv_->text = new LyXText(bv_);
308         } else {
309                 // See if we have a text in TextCache that fits
310                 // the new buffer_ with the correct width.
311                 bv_->text = textcache.findFit(buffer_, workarea_.workWidth());
312                 if (bv_->text) {
313                         if (lyxerr.debugging()) {
314                                 lyxerr << "Found a LyXText that fits:\n";
315                                 textcache.show(lyxerr, make_pair(buffer_, make_pair(workarea_.workWidth(), bv_->text)));
316                         }
317                         // Set the owner of the newly found text
318                         //      bv_->text->owner(bv_);
319                         if (lyxerr.debugging())
320                                 textcache.show(lyxerr, "resizeCurrentBuffer");
321                 } else {
322                         bv_->text = new LyXText(bv_);
323                 }
324         }
325         updateScreen();
326
327         if (par) {
328                 bv_->text->selection.set(true);
329                 /* at this point just to avoid the Delete-Empty-Paragraph
330                  * Mechanism when setting the cursor */
331                 bv_->text->selection.mark(mark_set);
332                 if (selection) {
333                         bv_->text->setCursor(bv_, selstartpar, selstartpos);
334                         bv_->text->selection.cursor = bv_->text->cursor;
335                         bv_->text->setCursor(bv_, selendpar, selendpos);
336                         bv_->text->setSelection(bv_);
337                         bv_->text->setCursor(bv_, par, pos);
338                 } else {
339                         bv_->text->setCursor(bv_, par, pos);
340                         bv_->text->selection.cursor = bv_->text->cursor;
341                         bv_->text->selection.set(false);
342                 }
343                 // remake the inset locking
344                 bv_->theLockingInset(the_locking_inset);
345         }
346         bv_->text->first = screen_->TopCursorVisible(bv_->text);
347         buffer_->resizeInsets(bv_);
348         // this will scroll the screen such that the cursor becomes visible
349         updateScrollbar();
350         redraw();
351
352         setState();
353         AllowInput(bv_);
354
355         /// clear the "Formatting Document" message 
356         owner_->message("");
357  
358         /// get rid of the splash screen if it's not gone already
359         owner_->getDialogs()->destroySplash();
360  
361         return 0;
362 }
363
364
365 void BufferView::Pimpl::updateScreen()
366 {
367         // Regenerate the screen.
368         screen_.reset(new LyXScreen(workarea_));
369 }
370
371
372 void BufferView::Pimpl::updateScrollbar()
373 {
374         /* If the text is smaller than the working area, the scrollbar
375          * maximum must be the working area height. No scrolling will 
376          * be possible */
377
378         if (!bv_->text) {
379                 workarea_.setScrollbar(0, 1.0);
380                 return;
381         }
382
383         static unsigned long text_height;
384         static unsigned long work_height;
385
386         unsigned long const tmp_text_height = bv_->text->height;
387         long const tmp_scrollbar_value = bv_->text->first;
388         
389         // check if anything has changed.
390         if (text_height == tmp_text_height
391             && work_height == workarea_.height()
392             && current_scrollbar_value == tmp_scrollbar_value)
393                 return; // no
394
395         // update values
396         text_height = tmp_text_height;
397         work_height = workarea_.height();
398         current_scrollbar_value = tmp_scrollbar_value;
399
400         long const height_diff = text_height - work_height;
401
402         if (height_diff <= 0) {
403                 workarea_.setScrollbar(0, 1.0);
404                 return;
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) + work_height);
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 #ifndef NO_LATEX
1188             &&
1189             text->real_current_font.latex() != LyXFont::ON
1190 #endif
1191                 ) {
1192                 if (owner_->getIntl()->keymap == Intl::PRIMARY)
1193                         owner_->getIntl()->KeyMapSec();
1194         } else {
1195                 if (owner_->getIntl()->keymap == Intl::SECONDARY)
1196                         owner_->getIntl()->KeyMapPrim();
1197         }
1198 }
1199
1200
1201 void BufferView::Pimpl::insetSleep()
1202 {
1203         if (bv_->theLockingInset() && !inset_slept) {
1204                 bv_->theLockingInset()->getCursorPos(bv_, bv_->slx, bv_->sly);
1205                 bv_->theLockingInset()->insetUnlock(bv_);
1206                 inset_slept = true;
1207         }
1208 }
1209
1210
1211 void BufferView::Pimpl::insetWakeup()
1212 {
1213         if (bv_->theLockingInset() && inset_slept) {
1214                 bv_->theLockingInset()->edit(bv_, bv_->slx, bv_->sly, 0);
1215                 inset_slept = false;
1216         }
1217 }
1218
1219
1220 void BufferView::Pimpl::insetUnlock()
1221 {
1222         if (bv_->theLockingInset()) {
1223                 if (!inset_slept)
1224                         bv_->theLockingInset()->insetUnlock(bv_);
1225                 bv_->theLockingInset(0);
1226                 bv_->text->finishUndo();
1227                 inset_slept = false;
1228         }
1229 }
1230
1231
1232 bool BufferView::Pimpl::focus() const
1233 {
1234         return workarea_.hasFocus();
1235 }
1236
1237
1238 void BufferView::Pimpl::focus(bool f)
1239 {
1240         if (f) workarea_.setFocus();
1241 }
1242
1243
1244 bool BufferView::Pimpl::active() const
1245 {
1246         return workarea_.active();
1247 }
1248
1249
1250 bool BufferView::Pimpl::belowMouse() const 
1251 {
1252         return workarea_.belowMouse();
1253 }
1254
1255
1256 void BufferView::Pimpl::showCursor()
1257 {
1258         if (screen_.get())
1259                 screen_->ShowCursor(bv_->text, bv_);
1260 }
1261
1262
1263 void BufferView::Pimpl::hideCursor()
1264 {
1265         if (screen_.get())
1266                 screen_->HideCursor();
1267 }
1268
1269
1270 void BufferView::Pimpl::toggleSelection(bool b)
1271 {
1272         if (screen_.get())
1273                 screen_->ToggleSelection(bv_->text, bv_, b);
1274 }
1275
1276
1277 void BufferView::Pimpl::toggleToggle()
1278 {
1279         if (screen_.get())
1280                 screen_->ToggleToggle(bv_->text, bv_);
1281 }
1282
1283
1284 void BufferView::Pimpl::center() 
1285 {
1286         beforeChange(bv_->text);
1287         if (bv_->text->cursor.y() > static_cast<int>((workarea_.height() / 2))) {
1288                 screen_->Draw(bv_->text, bv_, bv_->text->cursor.y() - workarea_.height() / 2);
1289         } else {
1290                 screen_->Draw(bv_->text, bv_, 0);
1291         }
1292         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1293         redraw();
1294 }
1295
1296
1297 void BufferView::Pimpl::pasteClipboard(bool asPara) 
1298 {
1299         if (!buffer_) return;
1300
1301         screen_->HideCursor();
1302         beforeChange(bv_->text);
1303         
1304         string const clip(workarea_.getClipboard());
1305         
1306         if (clip.empty()) return;
1307
1308         if (asPara) {
1309                 bv_->text->insertStringAsParagraphs(bv_, clip);
1310         } else {
1311                 bv_->text->insertStringAsLines(bv_, clip);
1312         }
1313         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1314 }
1315
1316
1317 void BufferView::Pimpl::stuffClipboard(string const & stuff) const
1318 {
1319         workarea_.putClipboard(stuff);
1320 }
1321
1322
1323 /*
1324  * Dispatch functions for actions which can be valid for BufferView->text
1325  * and/or InsetText->text!!!
1326  */
1327
1328
1329 inline
1330 void BufferView::Pimpl::moveCursorUpdate(bool selecting)
1331 {
1332         LyXText * lt = bv_->getLyXText();
1333         
1334         if (selecting || lt->selection.mark()) {
1335                 lt->setSelection(bv_);
1336                 if (lt->bv_owner)
1337                         toggleToggle();
1338         }
1339         update(lt, BufferView::SELECT|BufferView::FITCUR);
1340         showCursor();
1341         
1342         /* ---> Everytime the cursor is moved, show the current font state. */
1343         // should this too me moved out of this func?
1344         //owner->showState();
1345         setState();
1346 }
1347
1348
1349 Inset * BufferView::Pimpl::getInsetByCode(Inset::Code code)
1350 {
1351         LyXCursor cursor = bv_->getLyXText()->cursor;
1352         Buffer::inset_iterator it =
1353                 find_if(Buffer::inset_iterator(
1354                         cursor.par(), cursor.pos()),
1355                         buffer_->inset_iterator_end(),
1356                         lyx::compare_memfun(&Inset::lyxCode, code));
1357         return it != buffer_->inset_iterator_end() ? (*it) : 0;
1358 }
1359
1360
1361 void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
1362 {
1363         string filename = filen;
1364
1365         if (filename.empty()) {
1366                 // Launch a file browser
1367                 string initpath = lyxrc.document_path;
1368
1369                 if (available()) {
1370                         string const trypath = owner_->buffer()->filepath;
1371                         // If directory is writeable, use this as default.
1372                         if (IsDirWriteable(trypath) == 1)
1373                                 initpath = trypath;
1374                 }
1375
1376                 FileDialog fileDlg(bv_->owner(),
1377                                    _("Select LyX document to insert"),
1378                         LFUN_FILE_INSERT,
1379                         make_pair(string(_("Documents")),
1380                                   string(lyxrc.document_path)),
1381                         make_pair(string(_("Examples")),
1382                                   string(AddPath(system_lyxdir, "examples"))));
1383
1384                 FileDialog::Result result =
1385                         fileDlg.Select(initpath,
1386                                        _("*.lyx| LyX Documents (*.lyx)"));
1387  
1388                 if (result.first == FileDialog::Later)
1389                         return;
1390
1391                 filename = result.second;
1392
1393                 // check selected filename
1394                 if (filename.empty()) {
1395                         owner_->message(_("Canceled."));
1396                         return;
1397                 }
1398         }
1399
1400         // get absolute path of file and add ".lyx" to the filename if
1401         // necessary
1402         filename = FileSearch(string(), filename, "lyx");
1403
1404         string const disp_fn(MakeDisplayPath(filename));
1405         
1406         ostringstream s1;
1407         s1 << _("Inserting document") << ' '
1408            << disp_fn << " ...";
1409         owner_->message(s1.str().c_str());
1410         bool const res = bv_->insertLyXFile(filename);
1411         if (res) {
1412                 ostringstream str;
1413                 str << _("Document") << ' ' << disp_fn
1414                     << ' ' << _("inserted.");
1415                 owner_->message(str.str().c_str());
1416         } else {
1417                 ostringstream str;
1418                 str << _("Could not insert document") << ' '
1419                     << disp_fn;
1420                 owner_->message(str.str().c_str());
1421         }
1422 }
1423
1424
1425 bool BufferView::Pimpl::Dispatch(kb_action action, string const & argument)
1426 {
1427         lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch: action["
1428                               << action <<"] arg[" << argument << "]" << endl;
1429         
1430         switch (action) {
1431                 // --- Misc -------------------------------------------
1432         case LFUN_APPENDIX:
1433         {
1434                 if (available()) {
1435                         LyXText * lt = bv_->getLyXText();
1436                         lt->toggleAppendix(bv_);
1437                         update(lt,
1438                                BufferView::SELECT
1439                                | BufferView::FITCUR
1440                                | BufferView::CHANGE);
1441                 }
1442         }
1443         break;
1444
1445         case LFUN_TOC_INSERT:
1446         {
1447                 InsetCommandParams p;
1448                 p.setCmdName("tableofcontents");
1449                 Inset * inset = new InsetTOC(p);
1450                 if (!insertInset(inset, "Standard"))
1451                         delete inset;
1452                 break;
1453         }
1454                 
1455         case LFUN_TABULAR_FEATURE:
1456         case LFUN_SCROLL_INSET:
1457                 // this is not handled here as this funktion is only aktive
1458                 // if we have a locking_inset and that one is (or contains)
1459                 // a tabular-inset
1460                 break;
1461
1462         case LFUN_INSET_GRAPHICS:
1463         {
1464                 Inset * new_inset = new InsetGraphics;
1465                 if (!insertInset(new_inset)) {
1466                         delete new_inset;
1467                 } else {
1468                         // this is need because you don't use a inset->Edit()
1469                         updateInset(new_inset, true);
1470                         new_inset->edit(bv_, 0, 0, 0);
1471                 }
1472                 break;
1473         }
1474                 
1475         case LFUN_PASTE:
1476                 bv_->paste();
1477                 setState();
1478                 break;
1479                 
1480         case LFUN_PASTESELECTION:
1481         {
1482                 bool asPara = false;
1483                 if (argument == "paragraph") asPara = true;
1484                 pasteClipboard(asPara);
1485         }
1486         break;
1487         
1488         case LFUN_CUT:
1489                 bv_->cut();
1490                 break;
1491                 
1492         case LFUN_COPY:
1493                 bv_->copy();
1494                 break;
1495                 
1496         case LFUN_LAYOUT_COPY:
1497                 bv_->copyEnvironment();
1498                 break;
1499                 
1500         case LFUN_LAYOUT_PASTE:
1501                 bv_->pasteEnvironment();
1502                 setState();
1503                 break;
1504                 
1505         case LFUN_GOTOERROR:
1506                 gotoInset(Inset::ERROR_CODE, false);
1507                 break;
1508                 
1509         case LFUN_GOTONOTE:
1510                 gotoInset(Inset::IGNORE_CODE, false);
1511                 break;
1512
1513         case LFUN_REFERENCE_GOTO:
1514         {
1515                 vector<Inset::Code> tmp;
1516                 tmp.push_back(Inset::LABEL_CODE);
1517                 tmp.push_back(Inset::REF_CODE);
1518                 gotoInset(tmp, true);
1519                 break;
1520         }
1521
1522         case LFUN_HYPHENATION:
1523                 hyphenationPoint();
1524                 break;
1525                 
1526         case LFUN_LDOTS:
1527                 ldots();
1528                 break;
1529                 
1530         case LFUN_END_OF_SENTENCE:
1531                 endOfSentenceDot();
1532                 break;
1533
1534         case LFUN_MENU_SEPARATOR:
1535                 menuSeparator();
1536                 break;
1537                 
1538         case LFUN_HFILL:
1539                 hfill();
1540                 break;
1541                 
1542         case LFUN_DEPTH:
1543                 changeDepth(bv_, bv_->getLyXText(), 0);
1544                 break;
1545                 
1546         case LFUN_DEPTH_MIN:
1547                 changeDepth(bv_, bv_->getLyXText(), -1);
1548                 break;
1549                 
1550         case LFUN_DEPTH_PLUS:
1551                 changeDepth(bv_, bv_->getLyXText(), 1);
1552                 break;
1553                 
1554         case LFUN_FREE:
1555                 owner_->getDialogs()->setUserFreeFont();
1556                 break;
1557
1558 #ifndef NO_LATEX
1559         case LFUN_TEX:
1560                 Tex(bv_);
1561                 setState();
1562                 owner_->showState();
1563                 break;
1564 #endif
1565                 
1566         case LFUN_FILE_INSERT:
1567         {
1568                 MenuInsertLyXFile(argument);
1569         }
1570         break;
1571         
1572         case LFUN_FILE_INSERT_ASCII_PARA:
1573                 InsertAsciiFile(bv_, argument, true);
1574                 break;
1575
1576         case LFUN_FILE_INSERT_ASCII:
1577                 InsertAsciiFile(bv_, argument, false);
1578                 break;
1579                 
1580         case LFUN_LAYOUT:
1581         {
1582                 lyxerr[Debug::INFO] << "LFUN_LAYOUT: (arg) "
1583                                     << argument << endl;
1584                 
1585                 // Derive layout number from given argument (string)
1586                 // and current buffer's textclass (number). */    
1587                 LyXTextClassList::ClassList::size_type tclass =
1588                         buffer_->params.textclass;
1589                 pair <bool, LyXTextClass::size_type> layout = 
1590                         textclasslist.NumberOfLayout(tclass, argument);
1591
1592                 // If the entry is obsolete, use the new one instead.
1593                 if (layout.first) {
1594                         string obs = textclasslist.Style(tclass,layout.second)
1595                                 .obsoleted_by();
1596                         if (!obs.empty()) 
1597                                 layout = 
1598                                         textclasslist.NumberOfLayout(tclass, obs);
1599                 }
1600
1601                 // see if we found the layout number:
1602                 if (!layout.first) {
1603                         owner_->getLyXFunc()->setErrorMessage(
1604                                 string(N_("Layout ")) + argument +
1605                                 N_(" not known"));
1606                         break;
1607                 }
1608
1609                 if (current_layout != layout.second) {
1610                         LyXText * lt = bv_->getLyXText();
1611                         hideCursor();
1612                         current_layout = layout.second;
1613                         update(lt,
1614                                BufferView::SELECT
1615                                | BufferView::FITCUR);
1616                         lt->setLayout(bv_, layout.second);
1617                         owner_->setLayout(layout.second);
1618                         update(lt,
1619                                BufferView::SELECT
1620                                | BufferView::FITCUR
1621                                | BufferView::CHANGE);
1622                         setState();
1623                 }
1624         }
1625         break;
1626
1627         case LFUN_LANGUAGE:
1628                 Lang(bv_, argument);
1629                 setState();
1630                 owner_->showState();
1631                 break;
1632
1633         case LFUN_EMPH:
1634                 Emph(bv_);
1635                 owner_->showState();
1636                 break;
1637
1638         case LFUN_BOLD:
1639                 Bold(bv_);
1640                 owner_->showState();
1641                 break;
1642                 
1643         case LFUN_NOUN:
1644                 Noun(bv_);
1645                 owner_->showState();
1646                 break;
1647                 
1648         case LFUN_CODE:
1649                 Code(bv_);
1650                 owner_->showState();
1651                 break;
1652                 
1653         case LFUN_SANS:
1654                 Sans(bv_);
1655                 owner_->showState();
1656                 break;
1657                 
1658         case LFUN_ROMAN:
1659                 Roman(bv_);
1660                 owner_->showState();
1661                 break;
1662                 
1663         case LFUN_DEFAULT:
1664                 StyleReset(bv_);
1665                 owner_->showState();
1666                 break;
1667                 
1668         case LFUN_UNDERLINE:
1669                 Underline(bv_);
1670                 owner_->showState();
1671                 break;
1672                 
1673         case LFUN_FONT_SIZE:
1674                 FontSize(bv_, argument);
1675                 owner_->showState();
1676                 break;
1677                 
1678         case LFUN_FONT_STATE:
1679                 owner_->getLyXFunc()->setMessage(CurrentState(bv_));
1680                 break;
1681                 
1682         case LFUN_UPCASE_WORD:
1683         {
1684                 LyXText * lt = bv_->getLyXText();
1685                 
1686                 update(lt,
1687                        BufferView::SELECT
1688                        | BufferView::FITCUR);
1689                 lt->changeCase(bv_, LyXText::text_uppercase);
1690                 if (lt->inset_owner)
1691                         updateInset(lt->inset_owner, true);
1692                 update(lt,
1693                        BufferView::SELECT
1694                        | BufferView::FITCUR
1695                        | BufferView::CHANGE);
1696         }
1697         break;
1698                 
1699         case LFUN_LOWCASE_WORD:
1700         {
1701                 LyXText * lt = bv_->getLyXText();
1702                 
1703                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1704                 lt->changeCase(bv_, LyXText::text_lowercase);
1705                 if (lt->inset_owner)
1706                         updateInset(lt->inset_owner, true);
1707                 update(lt,
1708                        BufferView::SELECT
1709                        | BufferView::FITCUR
1710                        | BufferView::CHANGE);
1711         }
1712         break;
1713                 
1714         case LFUN_CAPITALIZE_WORD:
1715         {
1716                 LyXText * lt = bv_->getLyXText();
1717                 
1718                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1719                 lt->changeCase(bv_, LyXText::text_capitalization);
1720                 if (lt->inset_owner)
1721                         updateInset(lt->inset_owner, true);
1722                 update(lt,
1723                        BufferView::SELECT
1724                        | BufferView::FITCUR
1725                        | BufferView::CHANGE);
1726         }
1727         break;
1728
1729         case LFUN_TRANSPOSE_CHARS:
1730         {
1731                 LyXText * lt = bv_->getLyXText();
1732                 
1733                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1734                 lt->transposeChars(*bv_);
1735                 if (lt->inset_owner)
1736                         updateInset(lt->inset_owner, true);
1737                 update(lt,
1738                        BufferView::SELECT
1739                        | BufferView::FITCUR
1740                        | BufferView::CHANGE);
1741         }
1742         break;
1743                 
1744                                           
1745         case LFUN_INSERT_LABEL:
1746                 MenuInsertLabel(bv_, argument);
1747                 break;
1748                 
1749         case LFUN_REF_INSERT:
1750                 if (argument.empty()) {
1751                         InsetCommandParams p("ref");
1752                         owner_->getDialogs()->createRef(p.getAsString());
1753                 } else {
1754                         InsetCommandParams p;
1755                         p.setFromString(argument);
1756
1757                         InsetRef * inset = new InsetRef(p, *buffer_);
1758                         if (!insertInset(inset))
1759                                 delete inset;
1760                         else
1761                                 updateInset(inset, true);
1762                 }
1763                 break;
1764
1765         case LFUN_BOOKMARK_SAVE:
1766                 savePosition(strToUnsignedInt(argument));
1767                 break;
1768
1769         case LFUN_BOOKMARK_GOTO:
1770                 restorePosition(strToUnsignedInt(argument));
1771                 break;
1772
1773         case LFUN_REF_GOTO:
1774         {
1775                 string label(argument);
1776                 if (label.empty()) {
1777                         InsetRef * inset = 
1778                                 static_cast<InsetRef*>(getInsetByCode(Inset::REF_CODE));
1779                         if (inset) {
1780                                 label = inset->getContents();
1781                                 savePosition(0);
1782                         }
1783                 }
1784                 
1785                 if (!label.empty()) {
1786                         //bv_->savePosition(0);
1787                         if (!bv_->gotoLabel(label))
1788                                 WriteAlert(_("Error"), 
1789                                            _("Couldn't find this label"), 
1790                                            _("in current document."));
1791                 }
1792         }
1793         break;
1794                 
1795                 // --- Cursor Movements -----------------------------
1796         case LFUN_RIGHT:
1797         {
1798                 LyXText * lt = bv_->getLyXText();
1799                 
1800                 bool is_rtl = lt->cursor.par()->isRightToLeftPar(buffer_->params);
1801                 if (!lt->selection.mark())
1802                         beforeChange(lt);
1803                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1804                 if (is_rtl)
1805                         lt->cursorLeft(bv_, false);
1806                 if (lt->cursor.pos() < lt->cursor.par()->size()
1807                     && lt->cursor.par()->getChar(lt->cursor.pos())
1808                     == Paragraph::META_INSET
1809                     && lt->cursor.par()->getInset(lt->cursor.pos())
1810                     && lt->cursor.par()->getInset(lt->cursor.pos())->editable() == Inset::HIGHLY_EDITABLE){
1811                         Inset * tmpinset = lt->cursor.par()->getInset(lt->cursor.pos());
1812                         owner_->getLyXFunc()->setMessage(tmpinset->editMessage());
1813                         int y = 0;
1814                         if (is_rtl) {
1815                                 LyXFont const font = 
1816                                         lt->getFont(buffer_,
1817                                                     lt->cursor.par(),
1818                                                     lt->cursor.pos());  
1819                                 y = tmpinset->descent(bv_,font);
1820                         }
1821                         tmpinset->edit(bv_, 0, y, 0);
1822                         break;
1823                 }
1824                 if (!is_rtl)
1825                         lt->cursorRight(bv_, false);
1826                 lt->finishUndo();
1827                 moveCursorUpdate(false);
1828                 owner_->showState();
1829         }
1830         break;
1831                 
1832         case LFUN_LEFT:
1833         {
1834                 // This is soooo ugly. Isn`t it possible to make
1835                 // it simpler? (Lgb)
1836                 LyXText * lt = bv_->getLyXText();
1837                 bool is_rtl = lt->cursor.par()->isRightToLeftPar(buffer_->params);
1838                 if (!lt->selection.mark())
1839                         beforeChange(lt);
1840                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1841                 LyXCursor const cur = lt->cursor;
1842                 if (!is_rtl)
1843                         lt->cursorLeft(bv_, false);
1844                 if ((is_rtl || cur != lt->cursor) && // only if really moved!
1845                     lt->cursor.pos() < lt->cursor.par()->size() &&
1846                     (lt->cursor.par()->getChar(lt->cursor.pos()) ==
1847                      Paragraph::META_INSET) &&
1848                     lt->cursor.par()->getInset(lt->cursor.pos()) &&
1849                     (lt->cursor.par()->getInset(lt->cursor.pos())->editable()
1850                      == Inset::HIGHLY_EDITABLE))
1851                 {
1852                         Inset * tmpinset = lt->cursor.par()->getInset(lt->cursor.pos());
1853                         owner_->getLyXFunc()->setMessage(tmpinset->editMessage());
1854                         LyXFont const font = lt->getFont(buffer_,
1855                                                          lt->cursor.par(),
1856                                                          lt->cursor.pos());
1857                         int y = is_rtl ? 0 
1858                                 : tmpinset->descent(bv_,font);
1859                         tmpinset->edit(bv_,
1860                                        tmpinset->x() +
1861                                        tmpinset->width(bv_,font),
1862                                        y, 0);
1863                         break;
1864                 }
1865                 if  (is_rtl)
1866                         lt->cursorRight(bv_, false);
1867
1868                 lt->finishUndo();
1869                 moveCursorUpdate(false);
1870                 owner_->showState();
1871         }
1872         break;
1873                 
1874         case LFUN_UP:
1875         {
1876                 LyXText * lt = bv_->getLyXText();
1877                 
1878                 if (!lt->selection.mark())
1879                         beforeChange(lt);
1880                 update(lt, BufferView::UPDATE);
1881                 lt->cursorUp(bv_);
1882                 lt->finishUndo();
1883                 moveCursorUpdate(false);
1884                 owner_->showState();
1885         }
1886         break;
1887                 
1888         case LFUN_DOWN:
1889         {
1890                 LyXText * lt = bv_->getLyXText();
1891                 
1892                 if (!lt->selection.mark())
1893                         beforeChange(lt);
1894                 update(lt, BufferView::UPDATE);
1895                 lt->cursorDown(bv_);
1896                 lt->finishUndo();
1897                 moveCursorUpdate(false);
1898                 owner_->showState();
1899         }
1900         break;
1901
1902         case LFUN_UP_PARAGRAPH:
1903         {
1904                 LyXText * lt = bv_->getLyXText();
1905                 
1906                 if (!lt->selection.mark())
1907                         beforeChange(lt);
1908                 update(lt, BufferView::UPDATE);
1909                 lt->cursorUpParagraph(bv_);
1910                 lt->finishUndo();
1911                 moveCursorUpdate(false);
1912                 owner_->showState();
1913         }
1914         break;
1915                 
1916         case LFUN_DOWN_PARAGRAPH:
1917         {
1918                 LyXText * lt = bv_->getLyXText();
1919                 
1920                 if (!lt->selection.mark())
1921                         beforeChange(lt);
1922                 update(lt, BufferView::UPDATE);
1923                 lt->cursorDownParagraph(bv_);
1924                 lt->finishUndo();
1925                 moveCursorUpdate(false);
1926                 owner_->showState();
1927         }
1928         break;
1929                 
1930         case LFUN_PRIOR:
1931         {
1932                 LyXText * lt = bv_->getLyXText();
1933                 
1934                 if (!lt->selection.mark())
1935                         beforeChange(lt);
1936                 update(lt, BufferView::UPDATE);
1937                 cursorPrevious(lt);
1938                 lt->finishUndo();
1939                 moveCursorUpdate(false);
1940                 owner_->showState();
1941         }
1942         break;
1943                 
1944         case LFUN_NEXT:
1945         {
1946                 LyXText * lt = bv_->getLyXText();
1947                 
1948                 if (!lt->selection.mark())
1949                         beforeChange(lt);
1950                 update(lt, BufferView::UPDATE);
1951                 cursorNext(lt);
1952                 lt->finishUndo();
1953                 moveCursorUpdate(false);
1954                 owner_->showState();
1955         }
1956         break;
1957                 
1958         case LFUN_HOME:
1959         {
1960                 LyXText * lt = bv_->getLyXText();
1961                 
1962                 if (!lt->selection.mark())
1963                         beforeChange(lt);
1964                 update(lt, BufferView::SELECT|BufferView::FITCUR);
1965                 lt->cursorHome(bv_);
1966                 lt->finishUndo();
1967                 moveCursorUpdate(false);
1968                 owner_->showState();
1969         }
1970         break;
1971                 
1972         case LFUN_END:
1973         {
1974                 LyXText * lt = bv_->getLyXText();
1975                 
1976                 if (!lt->selection.mark())
1977                         beforeChange(lt);
1978                 update(lt,
1979                        BufferView::SELECT|BufferView::FITCUR);
1980                 lt->cursorEnd(bv_);
1981                 lt->finishUndo();
1982                 moveCursorUpdate(false);
1983                 owner_->showState();
1984         }
1985         break;
1986                 
1987         case LFUN_SHIFT_TAB:
1988         case LFUN_TAB:
1989         {
1990                 LyXText * lt = bv_->getLyXText();
1991                 
1992                 if (!lt->selection.mark())
1993                         beforeChange(lt);
1994                 update(lt,
1995                        BufferView::SELECT|BufferView::FITCUR);
1996                 lt->cursorTab(bv_);
1997                 lt->finishUndo();
1998                 moveCursorUpdate(false);
1999                 owner_->showState();
2000         }
2001         break;
2002                 
2003         case LFUN_WORDRIGHT:
2004         {
2005                 LyXText * lt = bv_->getLyXText();
2006                 
2007                 if (!lt->selection.mark())
2008                         beforeChange(lt);
2009                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2010                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2011                         lt->cursorLeftOneWord(bv_);
2012                 else
2013                         lt->cursorRightOneWord(bv_);
2014                 lt->finishUndo();
2015                 moveCursorUpdate(false);
2016                 owner_->showState();
2017         }
2018         break;
2019                 
2020         case LFUN_WORDLEFT:
2021         {
2022                 LyXText * lt = bv_->getLyXText();
2023                 
2024                 if (!lt->selection.mark())
2025                         beforeChange(lt);
2026                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2027                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2028                         lt->cursorRightOneWord(bv_);
2029                 else
2030                         lt->cursorLeftOneWord(bv_);
2031                 lt->finishUndo();
2032                 moveCursorUpdate(false);
2033                 owner_->showState();
2034         }
2035         break;
2036                 
2037         case LFUN_BEGINNINGBUF:
2038         {
2039                 LyXText * lt = bv_->getLyXText();
2040                 
2041                 if (!lt->selection.mark())
2042                         beforeChange(lt);
2043                 update(lt,
2044                        BufferView::SELECT|BufferView::FITCUR);
2045                 lt->cursorTop(bv_);
2046                 lt->finishUndo();
2047                 moveCursorUpdate(false);
2048                 owner_->showState();
2049         }
2050         break;
2051                 
2052         case LFUN_ENDBUF:
2053         {
2054                 LyXText * lt = bv_->getLyXText();
2055                 
2056                 if (!lt->selection.mark())
2057                         beforeChange(lt);
2058                 update(lt,
2059                        BufferView::SELECT|BufferView::FITCUR);
2060                 lt->cursorBottom(bv_);
2061                 lt->finishUndo();
2062                 moveCursorUpdate(false);
2063                 owner_->showState();
2064         }
2065         break;
2066       
2067                 /* cursor selection ---------------------------- */
2068         case LFUN_RIGHTSEL:
2069         {
2070                 LyXText * lt = bv_->getLyXText();
2071                 
2072                 update(lt,
2073                        BufferView::SELECT|BufferView::FITCUR);
2074                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2075                         lt->cursorLeft(bv_);
2076                 else
2077                         lt->cursorRight(bv_);
2078                 lt->finishUndo();
2079                 moveCursorUpdate(true);
2080                 owner_->showState();
2081         }
2082         break;
2083                 
2084         case LFUN_LEFTSEL:
2085         {
2086                 LyXText * lt = bv_->getLyXText();
2087                 
2088                 update(lt,
2089                        BufferView::SELECT|BufferView::FITCUR);
2090                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2091                         lt->cursorRight(bv_);
2092                 else
2093                         lt->cursorLeft(bv_);
2094                 lt->finishUndo();
2095                 moveCursorUpdate(true);
2096                 owner_->showState();
2097         }
2098         break;
2099                 
2100         case LFUN_UPSEL:
2101         {
2102                 LyXText * lt = bv_->getLyXText();
2103                 
2104                 update(lt,
2105                        BufferView::SELECT|BufferView::FITCUR);
2106                 lt->cursorUp(bv_);
2107                 lt->finishUndo();
2108                 moveCursorUpdate(true);
2109                 owner_->showState();
2110         }
2111         break;
2112                 
2113         case LFUN_DOWNSEL:
2114         {
2115                 LyXText * lt = bv_->getLyXText();
2116                 
2117                 update(lt,
2118                        BufferView::SELECT|BufferView::FITCUR);
2119                 lt->cursorDown(bv_);
2120                 lt->finishUndo();
2121                 moveCursorUpdate(true);
2122                 owner_->showState();
2123         }
2124         break;
2125
2126         case LFUN_UP_PARAGRAPHSEL:
2127         {
2128                 LyXText * lt = bv_->getLyXText();
2129                 
2130                 update(lt,
2131                        BufferView::SELECT|BufferView::FITCUR);
2132                 lt->cursorUpParagraph(bv_);
2133                 lt->finishUndo();
2134                 moveCursorUpdate(true);
2135                 owner_->showState();
2136         }
2137         break;
2138                 
2139         case LFUN_DOWN_PARAGRAPHSEL:
2140         {
2141                 LyXText * lt = bv_->getLyXText();
2142                 
2143                 update(lt,
2144                        BufferView::SELECT|BufferView::FITCUR);
2145                 lt->cursorDownParagraph(bv_);
2146                 lt->finishUndo();
2147                 moveCursorUpdate(true);
2148                 owner_->showState();
2149         }
2150         break;
2151                 
2152         case LFUN_PRIORSEL:
2153         {
2154                 LyXText * lt = bv_->getLyXText();
2155                 
2156                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2157                 cursorPrevious(lt);
2158                 lt->finishUndo();
2159                 moveCursorUpdate(true);
2160                 owner_->showState();
2161         }
2162         break;
2163                 
2164         case LFUN_NEXTSEL:
2165         {
2166                 LyXText * lt = bv_->getLyXText();
2167                 
2168                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2169                 cursorNext(lt);
2170                 lt->finishUndo();
2171                 moveCursorUpdate(true);
2172                 owner_->showState();
2173         }
2174         break;
2175                 
2176         case LFUN_HOMESEL:
2177         {
2178                 LyXText * lt = bv_->getLyXText();
2179                 
2180                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2181                 lt->cursorHome(bv_);
2182                 lt->finishUndo();
2183                 moveCursorUpdate(true);
2184                 owner_->showState();
2185         }
2186         break;
2187                 
2188         case LFUN_ENDSEL:
2189         {
2190                 LyXText * lt = bv_->getLyXText();
2191                 
2192                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2193                 lt->cursorEnd(bv_);
2194                 lt->finishUndo();
2195                 moveCursorUpdate(true);
2196                 owner_->showState();
2197         }
2198         break;
2199                 
2200         case LFUN_WORDRIGHTSEL:
2201         {
2202                 LyXText * lt = bv_->getLyXText();
2203                 
2204                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2205                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2206                         lt->cursorLeftOneWord(bv_);
2207                 else
2208                         lt->cursorRightOneWord(bv_);
2209                 lt->finishUndo();
2210                 moveCursorUpdate(true);
2211                 owner_->showState();
2212         }
2213         break;
2214                 
2215         case LFUN_WORDLEFTSEL:
2216         {
2217                 LyXText * lt = bv_->getLyXText();
2218                 
2219                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2220                 if (lt->cursor.par()->isRightToLeftPar(buffer_->params))
2221                         lt->cursorRightOneWord(bv_);
2222                 else
2223                         lt->cursorLeftOneWord(bv_);
2224                 lt->finishUndo();
2225                 moveCursorUpdate(true);
2226                 owner_->showState();
2227         }
2228         break;
2229                 
2230         case LFUN_BEGINNINGBUFSEL:
2231         {
2232                 LyXText * lt = bv_->getLyXText();
2233                 
2234                 if (lt->inset_owner)
2235                         break;
2236                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2237                 lt->cursorTop(bv_);
2238                 lt->finishUndo();
2239                 moveCursorUpdate(true);
2240                 owner_->showState();
2241         }
2242         break;
2243                 
2244         case LFUN_ENDBUFSEL:
2245         {
2246                 LyXText * lt = bv_->getLyXText();
2247                 
2248                 if (lt->inset_owner)
2249                         break;
2250                 update(lt,
2251                        BufferView::SELECT|BufferView::FITCUR);
2252                 lt->cursorBottom(bv_);
2253                 lt->finishUndo();
2254                 moveCursorUpdate(true);
2255                 owner_->showState();
2256         }
2257         break;
2258
2259                 // --- text changing commands ------------------------
2260         case LFUN_BREAKLINE:
2261         {
2262                 LyXText * lt = bv_->getLyXText();
2263
2264                 beforeChange(lt);
2265                 lt->insertChar(bv_, Paragraph::META_NEWLINE);
2266                 update(lt,
2267                        BufferView::SELECT
2268                        | BufferView::FITCUR
2269                        | BufferView::CHANGE);
2270                 moveCursorUpdate(false);
2271         }
2272         break;
2273                 
2274         case LFUN_PROTECTEDSPACE:
2275         {
2276                 LyXText * lt = bv_->getLyXText();
2277
2278                 LyXLayout const & style = textclasslist
2279                         .Style(buffer_->params.textclass,
2280                                lt->cursor.par()->getLayout());
2281
2282                 if (style.free_spacing) {
2283                         lt->insertChar(bv_, ' ');
2284                         update(lt,
2285                                BufferView::SELECT
2286                                | BufferView::FITCUR
2287                                | BufferView::CHANGE);
2288                 } else {
2289                         protectedBlank(lt);
2290                 }
2291                 moveCursorUpdate(false);
2292         }
2293         break;
2294                 
2295         case LFUN_SETMARK:
2296         {
2297                 LyXText * lt = bv_->getLyXText();
2298
2299                 if (lt->selection.mark()) {
2300                         beforeChange(lt);
2301                         update(lt,
2302                                BufferView::SELECT
2303                                | BufferView::FITCUR);
2304                         owner_->getLyXFunc()->setMessage(N_("Mark removed"));
2305                 } else {
2306                         beforeChange(lt);
2307                         lt->selection.mark(true);
2308                         update(lt,
2309                                BufferView::SELECT
2310                                | BufferView::FITCUR);
2311                         owner_->getLyXFunc()->setMessage(N_("Mark set"));
2312                 }
2313                 lt->selection.cursor = lt->cursor;
2314         }
2315         break;
2316                 
2317         case LFUN_DELETE:
2318         {
2319                 LyXText * lt = bv_->getLyXText();
2320
2321                 if (!lt->selection.set()) {
2322                         lt->Delete(bv_);
2323                         lt->selection.cursor = lt->cursor;
2324                         update(lt,
2325                                BufferView::SELECT
2326                                | BufferView::FITCUR
2327                                | BufferView::CHANGE);
2328                         // It is possible to make it a lot faster still
2329                         // just comment out the line below...
2330                         showCursor();
2331                 } else {
2332                         bv_->cut();
2333                 }
2334                 moveCursorUpdate(false);
2335                 owner_->showState();
2336                 setState();
2337         }
2338         break;
2339
2340         case LFUN_DELETE_SKIP:
2341         {
2342                 LyXText * lt = bv_->getLyXText();
2343
2344                 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
2345                 
2346                 LyXCursor cursor = lt->cursor;
2347
2348                 if (!lt->selection.set()) {
2349                         if (cursor.pos() == cursor.par()->size()) {
2350                                 lt->cursorRight(bv_);
2351                                 cursor = lt->cursor;
2352                                 if (cursor.pos() == 0
2353                                     && !(cursor.par()->params().spaceTop()
2354                                          == VSpace (VSpace::NONE))) {
2355                                         lt->setParagraph
2356                                                 (bv_,
2357                                                  cursor.par()->params().lineTop(),
2358                                                  cursor.par()->params().lineBottom(),
2359                                                  cursor.par()->params().pagebreakTop(), 
2360                                                  cursor.par()->params().pagebreakBottom(),
2361                                                  VSpace(VSpace::NONE), 
2362                                                  cursor.par()->params().spaceBottom(),
2363                                                  cursor.par()->params().align(), 
2364                                                  cursor.par()->params().labelWidthString(), 0);
2365                                         lt->cursorLeft(bv_);
2366                                         update(lt, 
2367                                                BufferView::SELECT
2368                                                | BufferView::FITCUR
2369                                                | BufferView::CHANGE);
2370                                 } else {
2371                                         lt->cursorLeft(bv_);
2372                                         lt->Delete(bv_);
2373                                         lt->selection.cursor = lt->cursor;
2374                                         update(lt,
2375                                                BufferView::SELECT
2376                                                | BufferView::FITCUR
2377                                                | BufferView::CHANGE);
2378                                 }
2379                         } else {
2380                                 lt->Delete(bv_);
2381                                 lt->selection.cursor = lt->cursor;
2382                                 update(lt,
2383                                        BufferView::SELECT
2384                                        | BufferView::FITCUR
2385                                        | BufferView::CHANGE);
2386                         }
2387                 } else {
2388                         bv_->cut();
2389                 }
2390         }
2391         break;
2392
2393         /* -------> Delete word forward. */
2394         case LFUN_DELETE_WORD_FORWARD:
2395                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
2396                 bv_->getLyXText()->deleteWordForward(bv_);
2397                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2398                 moveCursorUpdate(false);
2399                 owner_->showState();
2400                 break;
2401
2402                 /* -------> Delete word backward. */
2403         case LFUN_DELETE_WORD_BACKWARD:
2404         {
2405                 LyXText * lt = bv_->getLyXText();
2406                 
2407                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2408                 lt->deleteWordBackward(bv_);
2409                 update(lt,
2410                        BufferView::SELECT
2411                        | BufferView::FITCUR
2412                        | BufferView::CHANGE);
2413                 moveCursorUpdate(false);
2414                 owner_->showState();
2415         }
2416         break;
2417                 
2418                 /* -------> Kill to end of line. */
2419         case LFUN_DELETE_LINE_FORWARD:
2420         {
2421                 LyXText * lt = bv_->getLyXText();
2422                 
2423                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2424                 lt->deleteLineForward(bv_);
2425                 update(lt,
2426                        BufferView::SELECT
2427                        | BufferView::FITCUR
2428                        | BufferView::CHANGE);
2429                 moveCursorUpdate(false);
2430         }
2431         break;
2432                 
2433                 /* -------> Set mark off. */
2434         case LFUN_MARK_OFF:
2435         {
2436                 LyXText * lt = bv_->getLyXText();
2437                 
2438                 beforeChange(lt);
2439                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2440                 lt->selection.cursor = lt->cursor;
2441                 owner_->getLyXFunc()->setMessage(N_("Mark off"));
2442         }
2443         break;
2444
2445                 /* -------> Set mark on. */
2446         case LFUN_MARK_ON:
2447         {
2448                 LyXText * lt = bv_->getLyXText();
2449                 
2450                 beforeChange(lt);
2451                 lt->selection.mark(true);
2452                 update(lt, BufferView::SELECT|BufferView::FITCUR);
2453                 lt->selection.cursor = lt->cursor;
2454                 owner_->getLyXFunc()->setMessage(N_("Mark on"));
2455         }
2456         break;
2457                 
2458         case LFUN_BACKSPACE:
2459         {
2460                 LyXText * lt = bv_->getLyXText();
2461                 
2462                 if (!lt->selection.set()) {
2463                         if (owner_->getIntl()->getTrans().backspace()) {
2464                                 lt->backspace(bv_);
2465                                 lt->selection.cursor = lt->cursor;
2466                                 update(lt,
2467                                        BufferView::SELECT
2468                                        | BufferView::FITCUR
2469                                        | BufferView::CHANGE);
2470                                 // It is possible to make it a lot faster still
2471                                 // just comment out the line below...
2472                                 showCursor();
2473                         }
2474                 } else {
2475                         bv_->cut();
2476                 }
2477                 owner_->showState();
2478                 setState();
2479         }
2480         break;
2481
2482         case LFUN_BACKSPACE_SKIP:
2483         {
2484                 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
2485                 LyXText * lt = bv_->getLyXText();
2486                 
2487                 LyXCursor cursor = lt->cursor;
2488                 
2489                 if (!lt->selection.set()) {
2490                         if (cursor.pos() == 0 
2491                             && !(cursor.par()->params().spaceTop() 
2492                                  == VSpace (VSpace::NONE))) {
2493                                 lt->setParagraph 
2494                                         (bv_,
2495                                          cursor.par()->params().lineTop(),      
2496                                          cursor.par()->params().lineBottom(),
2497                                          cursor.par()->params().pagebreakTop(), 
2498                                          cursor.par()->params().pagebreakBottom(),
2499                                          VSpace(VSpace::NONE), cursor.par()->params().spaceBottom(),
2500                                          cursor.par()->params().align(), 
2501                                          cursor.par()->params().labelWidthString(), 0);
2502                                 update(lt,
2503                                        BufferView::SELECT
2504                                        | BufferView::FITCUR
2505                                        | BufferView::CHANGE);
2506                         } else {
2507                                 lt->backspace(bv_);
2508                                 lt->selection.cursor = cursor;
2509                                 update(lt,
2510                                        BufferView::SELECT
2511                                        | BufferView::FITCUR
2512                                        | BufferView::CHANGE);
2513                         }
2514                 } else
2515                         bv_->cut();
2516         }
2517         break;
2518
2519         case LFUN_BREAKPARAGRAPH:
2520         {
2521                 LyXText * lt = bv_->getLyXText();
2522                 
2523                 beforeChange(lt);
2524                 lt->breakParagraph(bv_, 0);
2525                 update(lt,
2526                        BufferView::SELECT
2527                        | BufferView::FITCUR
2528                        | BufferView::CHANGE);
2529                 lt->selection.cursor = lt->cursor;
2530                 setState();
2531                 owner_->showState();
2532                 break;
2533         }
2534
2535         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
2536         {
2537                 LyXText * lt = bv_->getLyXText();
2538                 
2539                 beforeChange(lt);
2540                 lt->breakParagraph(bv_, 1);
2541                 update(lt,
2542                        BufferView::SELECT
2543                        | BufferView::FITCUR
2544                        | BufferView::CHANGE);
2545                 lt->selection.cursor = lt->cursor;
2546                 setState();
2547                 owner_->showState();
2548                 break;
2549         }
2550         
2551         case LFUN_BREAKPARAGRAPH_SKIP:
2552         {
2553                 // When at the beginning of a paragraph, remove
2554                 // indentation and add a "defskip" at the top.
2555                 // Otherwise, do the same as LFUN_BREAKPARAGRAPH.
2556                 LyXText * lt = bv_->getLyXText();
2557                 
2558                 LyXCursor cursor = lt->cursor;
2559                 
2560                 beforeChange(lt);
2561                 if (cursor.pos() == 0) {
2562                         if (cursor.par()->params().spaceTop() == VSpace(VSpace::NONE)) {
2563                                 lt->setParagraph
2564                                         (bv_,
2565                                          cursor.par()->params().lineTop(),      
2566                                          cursor.par()->params().lineBottom(),
2567                                          cursor.par()->params().pagebreakTop(), 
2568                                          cursor.par()->params().pagebreakBottom(),
2569                                          VSpace(VSpace::DEFSKIP), cursor.par()->params().spaceBottom(),
2570                                          cursor.par()->params().align(), 
2571                                          cursor.par()->params().labelWidthString(), 1);
2572                                 //update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2573                         } 
2574                 }
2575                 else {
2576                         lt->breakParagraph(bv_, 0);
2577                         //update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2578                 }
2579
2580                 update(lt,
2581                        BufferView::SELECT
2582                        | BufferView::FITCUR
2583                        | BufferView::CHANGE);
2584                 lt->selection.cursor = cursor;
2585                 setState();
2586                 owner_->showState();
2587         }
2588         break;
2589
2590         case LFUN_PARAGRAPH_SPACING:
2591         {
2592                 LyXText * lt = bv_->getLyXText();
2593                 
2594                 Paragraph * par = lt->cursor.par();
2595                 Spacing::Space cur_spacing = par->params().spacing().getSpace();
2596                 float cur_value = 1.0;
2597                 if (cur_spacing == Spacing::Other) {
2598                         cur_value = par->params().spacing().getValue();
2599                 }
2600                 
2601                 istringstream istr(argument.c_str());
2602
2603                 string tmp;
2604                 istr >> tmp;
2605                 Spacing::Space new_spacing = cur_spacing;
2606                 float new_value = cur_value;
2607                 if (tmp.empty()) {
2608                         lyxerr << "Missing argument to `paragraph-spacing'"
2609                                << endl;
2610                 } else if (tmp == "single") {
2611                         new_spacing = Spacing::Single;
2612                 } else if (tmp == "onehalf") {
2613                         new_spacing = Spacing::Onehalf;
2614                 } else if (tmp == "double") {
2615                         new_spacing = Spacing::Double;
2616                 } else if (tmp == "other") {
2617                         new_spacing = Spacing::Other;
2618                         float tmpval = 0.0;
2619                         istr >> tmpval;
2620                         lyxerr << "new_value = " << tmpval << endl;
2621                         if (tmpval != 0.0)
2622                                 new_value = tmpval;
2623                 } else if (tmp == "default") {
2624                         new_spacing = Spacing::Default;
2625                 } else {
2626                         lyxerr << _("Unknown spacing argument: ")
2627                                << argument << endl;
2628                 }
2629                 if (cur_spacing != new_spacing || cur_value != new_value) {
2630                         par->params().spacing(Spacing(new_spacing, new_value));
2631                         lt->redoParagraph(bv_);
2632                         update(lt,
2633                                BufferView::SELECT
2634                                | BufferView::FITCUR
2635                                | BufferView::CHANGE);
2636                 }
2637         }
2638         break;
2639         
2640         case LFUN_QUOTE:
2641                 bv_->insertCorrectQuote();
2642                 break;
2643
2644         case LFUN_HTMLURL:
2645         case LFUN_URL:
2646         {
2647                 InsetCommandParams p;
2648                 if (action == LFUN_HTMLURL)
2649                         p.setCmdName("htmlurl");
2650                 else
2651                         p.setCmdName("url");
2652                 owner_->getDialogs()->createUrl( p.getAsString() );
2653         }
2654         break;
2655         
2656         case LFUN_INSERT_URL:
2657         {
2658                 InsetCommandParams p;
2659                 p.setFromString( argument );
2660
2661                 InsetUrl * inset = new InsetUrl( p );
2662                 if (!insertInset(inset))
2663                         delete inset;
2664                 else
2665                         updateInset( inset, true );
2666         }
2667         break;
2668         
2669         case LFUN_INSET_TEXT:
2670         {
2671                 InsetText * new_inset = new InsetText;
2672                 if (insertInset(new_inset))
2673                         new_inset->edit(bv_, 0, 0, 0);
2674                 else
2675                         delete new_inset;
2676         }
2677         break;
2678         
2679         case LFUN_INSET_ERT:
2680         {
2681                 InsetERT * new_inset = new InsetERT;
2682                 if (insertInset(new_inset))
2683                         new_inset->edit(bv_, 0, 0, 0);
2684                 else
2685                         delete new_inset;
2686         }
2687         break;
2688         
2689         case LFUN_INSET_EXTERNAL:
2690         {
2691                 InsetExternal * new_inset = new InsetExternal;
2692                 if (insertInset(new_inset))
2693                         new_inset->edit(bv_, 0, 0, 0);
2694                 else
2695                         delete new_inset;
2696         }
2697         break;
2698         
2699         case LFUN_INSET_FOOTNOTE:
2700         {
2701                 InsetFoot * new_inset = new InsetFoot;
2702                 if (insertInset(new_inset))
2703                         new_inset->edit(bv_, 0, 0, 0);
2704                 else
2705                         delete new_inset;
2706         }
2707         break;
2708
2709         case LFUN_INSET_MARGINAL:
2710         {
2711                 InsetMarginal * new_inset = new InsetMarginal;
2712                 if (insertInset(new_inset))
2713                         new_inset->edit(bv_, 0, 0, 0);
2714                 else
2715                         delete new_inset;
2716         }
2717         break;
2718
2719         case LFUN_INSET_MINIPAGE:
2720         {
2721                 InsetMinipage * new_inset = new InsetMinipage;
2722                 if (insertInset(new_inset))
2723                         new_inset->edit(bv_, 0, 0, 0);
2724                 else
2725                         delete new_inset;
2726         }
2727         break;
2728
2729         case LFUN_INSET_FLOAT:
2730         {
2731                 // check if the float type exist
2732                 if (floatList.typeExist(argument)) {
2733                         InsetFloat * new_inset = new InsetFloat(argument);
2734                         if (insertInset(new_inset))
2735                                 new_inset->edit(bv_, 0, 0, 0);
2736                         else
2737                                 delete new_inset;
2738                 } else {
2739                         lyxerr << "Non-existant float type: "
2740                                << argument << endl;
2741                 }
2742                 
2743         }
2744         break;
2745
2746         case LFUN_INSET_WIDE_FLOAT:
2747         {
2748                 // check if the float type exist
2749                 if (floatList.typeExist(argument)) {
2750                         InsetFloat * new_inset = new InsetFloat(argument);
2751                         new_inset->wide(true);
2752                         if (insertInset(new_inset))
2753                                 new_inset->edit(bv_, 0, 0, 0);
2754                         else
2755                                 delete new_inset;
2756                 } else {
2757                         lyxerr << "Non-existant float type: "
2758                                << argument << endl;
2759                 }
2760                 
2761         }
2762         break;
2763
2764         case LFUN_INSET_LIST:
2765         {
2766                 InsetList * new_inset = new InsetList;
2767                 if (insertInset(new_inset))
2768                         new_inset->edit(bv_, 0, 0, 0);
2769                 else
2770                         delete new_inset;
2771         }
2772         break;
2773
2774         case LFUN_INSET_THEOREM:
2775         {
2776                 InsetTheorem * new_inset = new InsetTheorem;
2777                 if (insertInset(new_inset))
2778                         new_inset->edit(bv_, 0, 0, 0);
2779                 else
2780                         delete new_inset;
2781         }
2782         break;
2783
2784         case LFUN_INSET_CAPTION:
2785         {
2786                 // Do we have a locking inset...
2787                 if (bv_->theLockingInset()) {
2788                         lyxerr << "Locking inset code: "
2789                                << static_cast<int>(bv_->theLockingInset()->lyxCode());
2790                         InsetCaption * new_inset = new InsetCaption;
2791                         new_inset->setOwner(bv_->theLockingInset());
2792                         new_inset->setAutoBreakRows(true);
2793                         new_inset->setDrawFrame(0, InsetText::LOCKED);
2794                         new_inset->setFrameColor(0, LColor::captionframe);
2795                         if (insertInset(new_inset))
2796                                 new_inset->edit(bv_, 0, 0, 0);
2797                         else
2798                                 delete new_inset;
2799                 }
2800         }
2801         break;
2802         
2803         case LFUN_INSET_TABULAR:
2804         {
2805                 int r = 2;
2806                 int c = 2;
2807                 if (!argument.empty())
2808                         ::sscanf(argument.c_str(),"%d%d", &r, &c);
2809                 InsetTabular * new_inset =
2810                         new InsetTabular(*buffer_, r, c);
2811                 bool const rtl =
2812                         bv_->getLyXText()->real_current_font.isRightToLeft();
2813                 if (!open_new_inset(new_inset, rtl))
2814                         delete new_inset;
2815         }
2816         break;
2817
2818         // --- lyxserver commands ----------------------------
2819
2820         case LFUN_CHARATCURSOR:
2821         {
2822                 Paragraph::size_type pos = bv_->getLyXText()->cursor.pos();
2823                 if (pos < bv_->getLyXText()->cursor.par()->size())
2824                         owner_->getLyXFunc()->setMessage(
2825                                 tostr(bv_->getLyXText()->cursor.par()->getChar(pos)));
2826                 else
2827                         owner_->getLyXFunc()->setMessage("EOF");
2828         }
2829         break;
2830         
2831         case LFUN_GETXY:
2832                 owner_->getLyXFunc()->setMessage(tostr(bv_->getLyXText()->cursor.x())
2833                                                  + ' '
2834                                                  + tostr(bv_->getLyXText()->cursor.y()));
2835                 break;
2836                 
2837         case LFUN_SETXY:
2838         {
2839                 int x = 0;
2840                 int y = 0;
2841                 if (::sscanf(argument.c_str(), " %d %d", &x, &y) != 2) {
2842                         lyxerr << "SETXY: Could not parse coordinates in '"
2843                                << argument << std::endl;
2844                 }
2845                 bv_->getLyXText()->setCursorFromCoordinates(bv_, x, y);
2846         }
2847         break;
2848         
2849         case LFUN_GETLAYOUT:
2850                 owner_->getLyXFunc()->setMessage(tostr(bv_->getLyXText()->cursor.par()->layout));
2851                 break;
2852                         
2853         case LFUN_GETFONT:
2854         {
2855                 LyXFont & font = bv_->getLyXText()->current_font;
2856                 if (font.shape() == LyXFont::ITALIC_SHAPE)
2857                         owner_->getLyXFunc()->setMessage("E");
2858                 else if (font.shape() == LyXFont::SMALLCAPS_SHAPE)
2859                         owner_->getLyXFunc()->setMessage("N");
2860                 else
2861                         owner_->getLyXFunc()->setMessage("0");
2862
2863         }
2864         break;
2865
2866         case LFUN_GETLATEX:
2867         {
2868 #ifndef NO_LATEX
2869                 LyXFont & font = bv_->getLyXText()->current_font;
2870                 if (font.latex() == LyXFont::ON)
2871                         owner_->getLyXFunc()->setMessage("L");
2872                 else
2873 #endif
2874                         owner_->getLyXFunc()->setMessage("0");
2875         }
2876         break;
2877
2878         // --- accented characters ---------------------------
2879                 
2880         case LFUN_UMLAUT:
2881         case LFUN_CIRCUMFLEX:
2882         case LFUN_GRAVE:
2883         case LFUN_ACUTE:
2884         case LFUN_TILDE:
2885         case LFUN_CEDILLA:
2886         case LFUN_MACRON:
2887         case LFUN_DOT:
2888         case LFUN_UNDERDOT:
2889         case LFUN_UNDERBAR:
2890         case LFUN_CARON:
2891         case LFUN_SPECIAL_CARON:
2892         case LFUN_BREVE:
2893         case LFUN_TIE:
2894         case LFUN_HUNG_UMLAUT:
2895         case LFUN_CIRCLE:
2896         case LFUN_OGONEK:
2897                 if (argument.empty()) {
2898                         // As always...
2899                         owner_->getLyXFunc()->handleKeyFunc(action);
2900                 } else {
2901                         owner_->getLyXFunc()->handleKeyFunc(action);
2902                         owner_->getIntl()->getTrans()
2903                                 .TranslateAndInsert(argument[0], bv_->getLyXText());
2904                         update(bv_->getLyXText(),
2905                                BufferView::SELECT
2906                                | BufferView::FITCUR
2907                                | BufferView::CHANGE);
2908                 }
2909                 break;
2910         
2911         // --- insert characters ----------------------------------------
2912         
2913         case LFUN_MATH_DELIM:     
2914         case LFUN_INSERT_MATRIX:
2915         {          
2916                 if (available()) { 
2917                         if (open_new_inset(new InsetFormula, false)) {
2918                                 bv_->theLockingInset()
2919                                         ->localDispatch(bv_, action, argument);
2920                         }
2921                 }
2922         }          
2923         break;
2924                
2925         case LFUN_INSERT_MATH:
2926         {
2927                 if (!available())
2928                         break;
2929  
2930                 InsetFormula * f = new InsetFormula(LM_OT_EQUATION);
2931                 open_new_inset(f);
2932                 f->localDispatch(bv_, LFUN_INSERT_MATH, argument);
2933         }
2934         break;
2935         
2936         case LFUN_MATH_DISPLAY:
2937         {       
2938                 if (available())
2939                         open_new_inset(new InsetFormula(LM_OT_EQUATION), false);
2940                 break;
2941         }
2942                     
2943         case LFUN_MATH_MACRO:
2944         {
2945                 if (available()) {
2946                         string s(argument);
2947                         if (s.empty())
2948                                 owner_->getLyXFunc()->setErrorMessage(N_("Missing argument"));
2949                         else {
2950                                 string const s1 = token(s, ' ', 1);
2951                                 int const na = s1.empty() ? 0 : lyx::atoi(s1);
2952                                 open_new_inset(new InsetFormulaMacro(token(s, ' ', 0), na), false);
2953                         }
2954                 }
2955         }
2956         break;
2957
2958         case LFUN_MATH_MODE:   // Open or create a math inset
2959         {               
2960                 if (available())
2961                         open_new_inset(new InsetFormula, false);
2962                 owner_->getLyXFunc()->setMessage(N_("Math editor mode"));
2963         }
2964         break;
2965           
2966         case LFUN_CITATION_INSERT:
2967         {
2968                 InsetCommandParams p;
2969                 p.setFromString( argument );
2970
2971                 InsetCitation * inset = new InsetCitation( p );
2972                 if (!insertInset(inset))
2973                         delete inset;
2974                 else
2975                         updateInset( inset, true );
2976         }
2977         break;
2978                     
2979         case LFUN_INSERT_BIBTEX:
2980         {   
2981                 // ale970405+lasgoutt970425
2982                 // The argument can be up to two tokens separated 
2983                 // by a space. The first one is the bibstyle.
2984                 string const db       = token(argument, ' ', 0);
2985                 string bibstyle = token(argument, ' ', 1);
2986                 if (bibstyle.empty())
2987                         bibstyle = "plain";
2988
2989                 InsetCommandParams p( "BibTeX", db, bibstyle );
2990                 InsetBibtex * inset = new InsetBibtex(p);
2991                 
2992                 if (insertInset(inset)) {
2993                         if (argument.empty())
2994                                 inset->edit(bv_, 0, 0, 0);
2995                 } else
2996                         delete inset;
2997         }
2998         break;
2999                 
3000         // BibTeX data bases
3001         case LFUN_BIBDB_ADD:
3002         {
3003                 InsetBibtex * inset = 
3004                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
3005                 if (inset) {
3006                         inset->addDatabase(argument);
3007                 }
3008         }
3009         break;
3010                     
3011         case LFUN_BIBDB_DEL:
3012         {
3013                 InsetBibtex * inset = 
3014                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
3015                 if (inset) {
3016                         inset->delDatabase(argument);
3017                 }
3018         }
3019         break;
3020         
3021         case LFUN_BIBTEX_STYLE:
3022         {
3023                 InsetBibtex * inset = 
3024                         static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
3025                 if (inset) {
3026                         inset->setOptions(argument);
3027                 }
3028         }
3029         break;
3030                 
3031         case LFUN_INDEX_CREATE:
3032         {
3033                 InsetCommandParams p( "index" );
3034                 
3035                 if (argument.empty()) {
3036                         // Get the word immediately preceding the cursor
3037                         Paragraph::size_type curpos = 
3038                                 bv_->getLyXText()->cursor.pos() - 1;
3039
3040                         string curstring;
3041                         if (curpos >= 0 )
3042                                 curstring = bv_->getLyXText()
3043                                         ->cursor.par()->getWord(curpos);
3044
3045                         p.setContents( curstring );
3046                 } else {
3047                         p.setContents( argument );
3048                 }
3049
3050                 owner_->getDialogs()->createIndex( p.getAsString() );
3051         }
3052         break;
3053                     
3054         case LFUN_INDEX_INSERT:
3055         {
3056                 InsetCommandParams p;
3057                 p.setFromString(argument);
3058                 InsetIndex * inset = new InsetIndex(p);
3059
3060                 if (!insertInset(inset))
3061                         delete inset;
3062                 else
3063                         updateInset(inset, true);
3064         }
3065         break;
3066                     
3067         case LFUN_INDEX_INSERT_LAST:
3068         {
3069                 // Get word immediately preceding the cursor
3070                 Paragraph::size_type curpos = 
3071                         bv_->getLyXText()->cursor.pos() - 1;
3072                 // Can't do that at the beginning of a paragraph
3073                 if (curpos < 0) break;
3074
3075                 string const curstring(bv_->getLyXText()
3076                                        ->cursor.par()->getWord(curpos));
3077
3078                 InsetCommandParams p("index", curstring);
3079                 InsetIndex * inset = new InsetIndex(p);
3080
3081                 if (!insertInset(inset))
3082                         delete inset;
3083                 else
3084                         updateInset(inset, true);
3085         }
3086         break;
3087
3088         case LFUN_INDEX_PRINT:
3089         {
3090                 InsetCommandParams p("printindex");
3091                 Inset * inset = new InsetPrintIndex(p);
3092                 if (!insertInset(inset, "Standard"))
3093                         delete inset;
3094         }
3095         break;
3096
3097         case LFUN_PARENTINSERT:
3098         {
3099                 lyxerr << "arg " << argument << endl;
3100                 InsetCommandParams p( "lyxparent", argument );
3101                 Inset * inset = new InsetParent(p, *buffer_);
3102                 if (!insertInset(inset, "Standard"))
3103                         delete inset;
3104         }
3105                  
3106         break;
3107
3108         case LFUN_CHILD_INSERT:
3109         {
3110                 InsetInclude::Params p;
3111                 p.cparams.setFromString(argument);
3112                 p.masterFilename_ = buffer_->fileName();
3113
3114                 InsetInclude * inset = new InsetInclude(p);
3115                 if (!insertInset(inset))
3116                         delete inset;
3117                 else {
3118                         updateInset(inset, true);
3119                         bv_->owner()->getDialogs()->showInclude(inset);
3120                 }
3121         }
3122         break; 
3123
3124         case LFUN_FLOAT_LIST:
3125         {
3126                 // We should check the argument for validity. (Lgb)
3127                 Inset * inset = new InsetFloatList(argument);
3128                 if (!insertInset(inset, "Standard"))
3129                         delete inset;
3130         }
3131         break;
3132         
3133         case LFUN_INSERT_NOTE:
3134                 insertNote();
3135                 break;
3136
3137         case LFUN_SELFINSERT:
3138         {
3139                 if (argument.empty()) break;
3140                 
3141                 /* Automatically delete the currently selected
3142                  * text and replace it with what is being
3143                  * typed in now. Depends on lyxrc settings
3144                  * "auto_region_delete", which defaults to
3145                  * true (on). */
3146
3147                 LyXText * lt = bv_->getLyXText();
3148                 
3149                 if (lyxrc.auto_region_delete) {
3150                         if (lt->selection.set()) {
3151                                 lt->cutSelection(bv_, false);
3152                                 bv_->update(lt,
3153                                             BufferView::SELECT
3154                                             | BufferView::FITCUR
3155                                             | BufferView::CHANGE);
3156                         }
3157                 }
3158                 
3159                 bv_->beforeChange(lt);
3160                 LyXFont const old_font(lt->real_current_font);
3161                 
3162                 string::const_iterator cit = argument.begin();
3163                 string::const_iterator end = argument.end();
3164                 for (; cit != end; ++cit) {
3165                         if (greek_kb_flag) {
3166                                 if (!math_insert_greek(bv_, *cit))
3167                                         owner_->getIntl()->getTrans().TranslateAndInsert(*cit, lt);
3168                         } else
3169                                 owner_->getIntl()->getTrans().TranslateAndInsert(*cit, lt);
3170                 }
3171                 
3172                 bv_->update(lt,
3173                             BufferView::SELECT
3174                             | BufferView::FITCUR
3175                             | BufferView::CHANGE);
3176                 
3177                 lt->selection.cursor = lt->cursor;
3178                 moveCursorUpdate(false);
3179                 
3180                 // real_current_font.number can change so we need to
3181                 // update the minibuffer
3182                 if (old_font != lt->real_current_font)
3183                         owner_->showState();
3184                 //return string();
3185         }
3186         break;
3187
3188         case LFUN_DATE_INSERT:  // jdblair: date-insert cmd
3189         {
3190                 time_t now_time_t = time(NULL);
3191                 struct tm * now_tm = localtime(&now_time_t);
3192                 setlocale(LC_TIME, "");
3193                 string arg;
3194                 if (!argument.empty())
3195                         arg = argument;
3196                 else 
3197                         arg = lyxrc.date_insert_format;
3198                 char datetmp[32];
3199                 int const datetmp_len =
3200                         ::strftime(datetmp, 32, arg.c_str(), now_tm);
3201
3202                 LyXText * lt = bv_->getLyXText();
3203                 
3204                 for (int i = 0; i < datetmp_len; i++) {
3205                         lt->insertChar(bv_, datetmp[i]);
3206                         update(lt,
3207                                BufferView::SELECT
3208                                | BufferView::FITCUR
3209                                | BufferView::CHANGE);
3210                 }
3211
3212                 lt->selection.cursor = lt->cursor;
3213                 moveCursorUpdate(false);
3214         }
3215         break;
3216
3217         case LFUN_UNKNOWN_ACTION:
3218                 owner_->getLyXFunc()->setErrorMessage(N_("Unknown function!"));
3219                 break;
3220         
3221         default:
3222                 return false;
3223         } // end of switch
3224
3225         return true;
3226 }
3227
3228
3229 void BufferView::Pimpl::newline()
3230 {
3231         if (available()) {
3232                 LyXText * lt = bv_->getLyXText();
3233                 hideCursor();
3234                 update(lt,
3235                        BufferView::SELECT
3236                        | BufferView::FITCUR);
3237                 lt->insertChar(bv_, Paragraph::META_NEWLINE);
3238                 update(lt,
3239                        BufferView::SELECT
3240                        | BufferView::FITCUR
3241                        | BufferView::CHANGE);
3242         }
3243 }
3244
3245
3246 void BufferView::Pimpl::hfill()
3247 {
3248         if (available()) {
3249                 LyXText * lt = bv_->getLyXText();
3250                 hideCursor();
3251                 update(lt,
3252                        BufferView::SELECT
3253                        | BufferView::FITCUR);
3254                 lt->insertChar(bv_, Paragraph::META_HFILL);
3255                 update(lt,
3256                        BufferView::SELECT
3257                        | BufferView::FITCUR
3258                        | BufferView::CHANGE);
3259         }
3260 }
3261
3262
3263 void BufferView::Pimpl::protectedBlank(LyXText * lt)
3264 {
3265         if (available()) {
3266                 hideCursor();
3267                 update(lt, BufferView::SELECT|BufferView::FITCUR);
3268                 InsetSpecialChar * new_inset =
3269                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
3270                 if (!insertInset(new_inset))
3271                         delete new_inset;
3272                 else
3273                         updateInset(new_inset, true);
3274         }
3275 }
3276
3277
3278 void BufferView::Pimpl::menuSeparator()
3279 {
3280         if (available()) {
3281                 LyXText * lt = bv_->getLyXText();
3282                 
3283                 hideCursor();
3284                 update(lt, BufferView::SELECT|BufferView::FITCUR);
3285                 InsetSpecialChar * new_inset = 
3286                         new InsetSpecialChar(InsetSpecialChar::MENU_SEPARATOR);
3287                 insertInset(new_inset);
3288         }
3289 }
3290
3291
3292 void BufferView::Pimpl::endOfSentenceDot()
3293 {
3294         if (available()) {
3295                 hideCursor();
3296                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
3297                 InsetSpecialChar * new_inset = 
3298                         new InsetSpecialChar(InsetSpecialChar::END_OF_SENTENCE);
3299                 insertInset(new_inset);
3300         }
3301 }
3302
3303
3304 void BufferView::Pimpl::ldots()
3305 {
3306         if (available())  {
3307                 hideCursor();
3308                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
3309                 InsetSpecialChar * new_inset = 
3310                         new InsetSpecialChar(InsetSpecialChar::LDOTS);
3311                 insertInset(new_inset);
3312         }
3313 }
3314
3315
3316 void BufferView::Pimpl::hyphenationPoint()
3317 {
3318         if (available()) {
3319                 hideCursor();
3320                 update(bv_->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
3321                 InsetSpecialChar * new_inset = 
3322                         new InsetSpecialChar(InsetSpecialChar::HYPHENATION);
3323                 insertInset(new_inset);
3324         }
3325 }
3326
3327
3328 void BufferView::Pimpl::insertNote()
3329 {
3330         InsetInfo * new_inset = new InsetInfo();
3331         insertInset(new_inset);
3332         new_inset->edit(bv_, 0, 0, 0);
3333 }
3334
3335
3336 // Open and lock an updatable inset
3337 bool BufferView::Pimpl::open_new_inset(UpdatableInset * new_inset, bool behind)
3338 {
3339         LyXText * lt = bv_->getLyXText();
3340         
3341         beforeChange(lt);
3342         lt->finishUndo();
3343         if (!insertInset(new_inset)) {
3344                 delete new_inset;
3345                 return false;
3346         }
3347         if (behind) {
3348                 LyXFont & font = lt->real_current_font;
3349                 new_inset->edit(bv_, new_inset->width(bv_, font), 0, 0);
3350         } else
3351                 new_inset->edit(bv_, 0, 0, 0);
3352         return true;
3353 }
3354
3355
3356 bool BufferView::Pimpl::insertInset(Inset * inset, string const & lout)
3357 {
3358         // if we are in a locking inset we should try to insert the
3359         // inset there otherwise this is a illegal function now
3360         if (bv_->theLockingInset()) {
3361                 if (bv_->theLockingInset()->insertInsetAllowed(inset))
3362                     return bv_->theLockingInset()->insertInset(bv_, inset);
3363                 return false;
3364         }
3365
3366         // not quite sure if we want this...
3367         bv_->text->setCursorParUndo(buffer_);
3368         bv_->text->freezeUndo();
3369         
3370         beforeChange(bv_->text);
3371         if (!lout.empty()) {
3372                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3373                 bv_->text->breakParagraph(bv_);
3374                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3375
3376                 if (bv_->text->cursor.par()->size()) {
3377                         bv_->text->cursorLeft(bv_);
3378                         
3379                         bv_->text->breakParagraph(bv_);
3380                         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3381                 }
3382
3383                 pair<bool, LyXTextClass::size_type> lres =
3384                         textclasslist.NumberOfLayout(buffer_->params
3385                                                      .textclass, lout);
3386                 LyXTextClass::size_type lay;
3387                 if (lres.first != false) {
3388                         // layout found
3389                         lay = lres.second;
3390                 } else {
3391                         // layout not fount using default "Standard" (0)
3392                         lay = 0;
3393                 }
3394                  
3395                 bv_->text->setLayout(bv_, lay);
3396                 
3397                 bv_->text->setParagraph(bv_, 0, 0,
3398                                    0, 0,
3399                                    VSpace(VSpace::NONE), VSpace(VSpace::NONE),
3400                                    LYX_ALIGN_LAYOUT, 
3401                                    string(),
3402                                    0);
3403                 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3404 #ifndef NO_LATEX
3405                 bv_->text->current_font.setLatex(LyXFont::OFF);
3406 #endif
3407         }
3408         
3409         bv_->text->insertInset(bv_, inset);
3410         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
3411
3412         bv_->text->unFreezeUndo();
3413         return true;
3414 }
3415
3416
3417 void BufferView::Pimpl::updateInset(Inset * inset, bool mark_dirty)
3418 {
3419         if (!inset)
3420                 return;
3421
3422         // first check for locking insets
3423         if (bv_->theLockingInset()) {
3424                 if (bv_->theLockingInset() == inset) {
3425                         if (bv_->text->updateInset(bv_, inset)) {
3426                                 update();
3427                                 if (mark_dirty) {
3428                                         buffer_->markDirty();
3429                                 }
3430                                 updateScrollbar();
3431                                 return;
3432                         }
3433                 } else if (bv_->theLockingInset()->updateInsetInInset(bv_, inset)) {
3434                         if (bv_->text->updateInset(bv_,
3435                                                    bv_->theLockingInset())) {
3436                                 update();
3437                                 if (mark_dirty){
3438                                         buffer_->markDirty();
3439                                 }
3440                                 updateScrollbar();
3441                                 return;
3442                         }
3443                 }
3444         }
3445   
3446         // then check the current buffer
3447         if (available()) {
3448                 hideCursor();
3449                 update(bv_->text, BufferView::UPDATE);
3450                 if (bv_->text->updateInset(bv_, inset)) {
3451                         if (mark_dirty) {
3452                                 update(bv_->text,
3453                                        BufferView::SELECT
3454                                        | BufferView::FITCUR
3455                                        | BufferView::CHANGE);
3456                         } else {
3457                                 update(bv_->text, SELECT);
3458                         }
3459                         return;
3460                 }
3461         }
3462 }
3463
3464
3465 void BufferView::Pimpl::gotoInset(vector<Inset::Code> const & codes,
3466                                   bool same_content)
3467 {
3468         if (!available()) return;
3469         
3470         hideCursor();
3471         beforeChange(bv_->text);
3472         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3473         
3474         string contents;
3475         if (same_content &&
3476             bv_->text->cursor.par()->getChar(bv_->text->cursor.pos()) == Paragraph::META_INSET) {
3477                 Inset const * inset = bv_->text->cursor.par()->getInset(bv_->text->cursor.pos());
3478                 if (find(codes.begin(), codes.end(), inset->lyxCode())
3479                     != codes.end())
3480                         contents =
3481                                 static_cast<InsetCommand const *>(inset)->getContents();
3482         }
3483         
3484         if (!bv_->text->gotoNextInset(bv_, codes, contents)) {
3485                 if (bv_->text->cursor.pos() 
3486                     || bv_->text->cursor.par() != bv_->text->firstParagraph()) {
3487                         LyXCursor tmp = bv_->text->cursor;
3488                         bv_->text->cursor.par(bv_->text->firstParagraph());
3489                         bv_->text->cursor.pos(0);
3490                         if (!bv_->text->gotoNextInset(bv_, codes, contents)) {
3491                                 bv_->text->cursor = tmp;
3492                                 bv_->owner()->message(_("No more insets"));
3493                         }
3494                 } else {
3495                         bv_->owner()->message(_("No more insets"));
3496                 }
3497         }
3498         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
3499         bv_->text->selection.cursor = bv_->text->cursor;
3500 }
3501
3502
3503 void BufferView::Pimpl::gotoInset(Inset::Code code, bool same_content)
3504 {
3505         gotoInset(vector<Inset::Code>(1, code), same_content);
3506 }