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