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