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