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