]> git.lyx.org Git - lyx.git/blob - src/BufferView_pimpl.C
simplify some, ws, begin minibuffer simplification
[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 "minibuffer.h"
21 #include "font.h"
22 #include "bufferview_funcs.h"
23 #include "TextCache.h"
24 #include "bufferlist.h"
25 #include "lyx_gui_misc.h"
26 #include "lyxrc.h"
27 #include "intl.h"
28 #include "support/LAssert.h"
29 #include "frontends/Dialogs.h"
30 #include "insets/insetbib.h"
31 #include "insets/insettext.h"
32 /// added for Dispatch functions
33 #include "lyx_cb.h"
34 #include "frontends/FileDialog.h"
35 #include "lyx_main.h"
36 #include "FloatList.h"
37 #include "support/filetools.h"
38 #include "support/lyxfunctional.h"
39 #include "insets/inseturl.h"
40 #include "insets/insetlatexaccent.h"
41 #include "insets/insettoc.h"
42 #include "insets/insetref.h"
43 #include "insets/insetparent.h"
44 #include "insets/insetindex.h"
45 #include "insets/insetinclude.h"
46 #include "insets/insetcite.h"
47 #include "insets/insetert.h"
48 #include "insets/insetexternal.h"
49 #include "insets/insetgraphics.h"
50 #include "insets/insetfoot.h"
51 #include "insets/insetmarginal.h"
52 #include "insets/insetminipage.h"
53 #include "insets/insetfloat.h"
54 #include "insets/insetlist.h"
55 #include "insets/insettabular.h"
56 #include "insets/insettheorem.h"
57 #include "insets/insetcaption.h"
58 #include "mathed/formulamacro.h"
59 extern LyXTextClass::size_type current_layout;
60 extern int greek_kb_flag;
61
62 using std::vector;
63 using std::find_if;
64 using std::pair;
65 using std::endl;
66 using std::make_pair;
67 using std::min;
68 using SigC::slot;
69
70 /* the selection possible is needed, that only motion events are 
71  * used, where the bottom press event was on the drawing area too */
72 bool selection_possible = false;
73
74 extern BufferList bufferlist;
75 extern char ascii_type;
76
77 extern bool math_insert_greek(BufferView *, char);
78 extern void sigchldhandler(pid_t pid, int * status);
79 extern int bibitemMaxWidth(BufferView *, LyXFont const &);
80
81 const unsigned int saved_positions_num = 20;
82
83 namespace {
84
85 inline
86 void waitForX()
87 {
88         XSync(fl_get_display(), 0);
89 }
90
91
92 void SetXtermCursor(Window win)
93 {
94         static Cursor cursor;
95         static bool cursor_undefined = true;
96         if (cursor_undefined){
97                 cursor = XCreateFontCursor(fl_get_display(), XC_xterm);
98                 XFlush(fl_get_display());
99                 cursor_undefined = false;
100         }
101         XDefineCursor(fl_get_display(), win, cursor);
102         XFlush(fl_get_display());
103 }
104
105 } // anon namespace
106
107
108 BufferView::Pimpl::Pimpl(BufferView * b, LyXView * o,
109              int xpos, int ypos, int width, int height)
110         : bv_(b), owner_(o), buffer_(0),
111           current_scrollbar_value(0), cursor_timeout(400),
112           workarea_(xpos, ypos, width, height), using_xterm_cursor(false)
113 {
114         // Setup the signals
115         workarea_.scrollCB.connect(slot(this, &BufferView::Pimpl::scrollCB));
116         workarea_.workAreaExpose
117                 .connect(slot(this, &BufferView::Pimpl::workAreaExpose));
118         workarea_.workAreaEnter
119                 .connect(slot(this, &BufferView::Pimpl::enterView));
120         workarea_.workAreaLeave
121                 .connect(slot(this, &BufferView::Pimpl::leaveView));
122         workarea_.workAreaButtonPress
123                 .connect(slot(this, &BufferView::Pimpl::workAreaButtonPress));
124         workarea_.workAreaButtonRelease
125                 .connect(slot(this,
126                               &BufferView::Pimpl::workAreaButtonRelease));
127         workarea_.workAreaMotionNotify
128                 .connect(slot(this, &BufferView::Pimpl::workAreaMotionNotify));
129         workarea_.workAreaDoubleClick
130                 .connect(slot(this, &BufferView::Pimpl::doubleClick));
131         workarea_.workAreaTripleClick
132                 .connect(slot(this, &BufferView::Pimpl::tripleClick));
133         workarea_.workAreaKeyPress
134                 .connect(slot(this, &BufferView::Pimpl::workAreaKeyPress));
135         
136         //screen_ = 0;
137
138         cursor_timeout.timeout.connect(slot(this,
139                                             &BufferView::Pimpl::cursorToggle));
140         //current_scrollbar_value = 0;
141         cursor_timeout.start();
142         workarea_.setFocus();
143         //using_xterm_cursor = false;
144         saved_positions.resize(saved_positions_num);
145 }
146
147
148 Painter & BufferView::Pimpl::painter() 
149 {
150         return workarea_.getPainter();
151 }
152
153
154 void BufferView::Pimpl::buffer(Buffer * b)
155 {
156         lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
157                             << b << ")" << endl;
158         if (buffer_) {
159                 bv_->insetSleep();
160                 buffer_->delUser(bv_);
161
162                 // Put the old text into the TextCache, but
163                 // only if the buffer is still loaded.
164                 // Also set the owner of the test to 0
165                 //              bv_->text->owner(0);
166                 textcache.add(buffer_, workarea_.workWidth(), bv_->text);
167                 if (lyxerr.debugging())
168                         textcache.show(lyxerr, "BufferView::buffer");
169                 
170                 bv_->text = 0;
171         }
172
173         // Set current buffer
174         buffer_ = b;
175
176         if (bufferlist.getState() == BufferList::CLOSING) return;
177         
178         // Nuke old image
179         // screen is always deleted when the buffer is changed.
180         screen_.reset(0);
181         //delete screen_;
182         //screen_ = 0;
183
184         // If we are closing the buffer, use the first buffer as current
185         if (!buffer_) {
186                 buffer_ = bufferlist.first();
187         }
188
189         if (buffer_) {
190                 lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl;
191                 buffer_->addUser(bv_);
192                 // If we don't have a text object for this, we make one
193                 if (bv_->text == 0) {
194                         resizeCurrentBuffer();
195                 } else {
196                         updateScreen();
197                         updateScrollbar();
198                 }
199                 bv_->text->first = screen_->TopCursorVisible(bv_->text);
200                 owner_->updateMenubar();
201                 owner_->updateToolbar();
202                 // Similarly, buffer-dependent dialogs should be updated or
203                 // hidden. This should go here because some dialogs (eg ToC)
204                 // require bv_->text.
205                 owner_->getDialogs()->updateBufferDependent(true);
206                 redraw();
207                 bv_->insetWakeup();
208         } else {
209                 lyxerr[Debug::INFO] << "  No Buffer!" << endl;
210                 owner_->updateMenubar();
211                 owner_->updateToolbar();
212                 owner_->getDialogs()->hideBufferDependent();
213                 updateScrollbar();
214                 workarea_.redraw();
215
216                 // Also remove all remaining text's from the testcache.
217                 // (there should not be any!) (if there is any it is a
218                 // bug!)
219                 if (lyxerr.debugging())
220                         textcache.show(lyxerr, "buffer delete all");
221                 textcache.clear();
222         }
223         // should update layoutchoice even if we don't have a buffer.
224         owner_->updateLayoutChoice();
225         owner_->getMiniBuffer()->Init();
226         owner_->updateWindowTitle();
227 }
228
229
230 void BufferView::Pimpl::resize(int xpos, int ypos, int width, int height)
231 {
232         workarea_.resize(xpos, ypos, width, height);
233         update(bv_->text, SELECT);
234         redraw();
235 }
236
237
238 void BufferView::Pimpl::resize()
239 {
240         if (buffer_)
241                 resizeCurrentBuffer();
242 }
243
244
245 void BufferView::Pimpl::redraw()
246 {
247         lyxerr[Debug::INFO] << "BufferView::redraw()" << endl;
248         workarea_.redraw();
249 }
250
251
252 bool BufferView::Pimpl::fitCursor(LyXText * text)
253 {
254         Assert(screen_.get());
255  
256         bool ret = screen_->FitCursor(text, bv_);
257         if (ret)
258             updateScrollbar();
259         return ret;
260 }
261
262
263 void BufferView::Pimpl::redoCurrentBuffer()
264 {
265         lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
266         if (buffer_ && bv_->text) {
267                 resize();
268                 owner_->updateLayoutChoice();
269         }
270 }
271
272
273 int BufferView::Pimpl::resizeCurrentBuffer()
274 {
275         lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
276         
277         LyXParagraph * par = 0;
278         LyXParagraph * selstartpar = 0;
279         LyXParagraph * selendpar = 0;
280         UpdatableInset * the_locking_inset = 0;
281         
282         LyXParagraph::size_type pos = 0;
283         LyXParagraph::size_type selstartpos = 0;
284         LyXParagraph::size_type selendpos = 0;
285         bool selection = false;
286         bool mark_set  = false;
287
288         ProhibitInput(bv_);
289
290         owner_->getMiniBuffer()->Set(_("Formatting document..."));   
291
292         if (bv_->text) {
293                 par = bv_->text->cursor.par();
294                 pos = bv_->text->cursor.pos();
295                 selstartpar = bv_->text->sel_start_cursor.par();
296                 selstartpos = bv_->text->sel_start_cursor.pos();
297                 selendpar = bv_->text->sel_end_cursor.par();
298                 selendpos = bv_->text->sel_end_cursor.pos();
299                 selection = bv_->text->selection;
300                 mark_set = bv_->text->mark_set;
301                 the_locking_inset = bv_->text->the_locking_inset;
302                 delete bv_->text;
303                 bv_->text = new LyXText(bv_);
304         } else {
305                 // See if we have a text in TextCache that fits
306                 // the new buffer_ with the correct width.
307                 bv_->text = textcache.findFit(buffer_, workarea_.workWidth());
308                 if (bv_->text) {
309                         if (lyxerr.debugging()) {
310                                 lyxerr << "Found a LyXText that fits:\n";
311                                 textcache.show(lyxerr, make_pair(buffer_, make_pair(workarea_.workWidth(), bv_->text)));
312                         }
313                         // Set the owner of the newly found text
314                         //      bv_->text->owner(bv_);
315                         if (lyxerr.debugging())
316                                 textcache.show(lyxerr, "resizeCurrentBuffer");
317                 } else {
318                         bv_->text = new LyXText(bv_);
319                 }
320         }
321         updateScreen();
322
323         if (par) {
324                 bv_->text->selection = true;
325                 /* at this point just to avoid the Delete-Empty-Paragraph
326                  * Mechanism when setting the cursor */
327                 bv_->text->mark_set = mark_set;
328                 if (selection) {
329                         bv_->text->SetCursor(bv_, selstartpar, selstartpos);
330                         bv_->text->sel_cursor = bv_->text->cursor;
331                         bv_->text->SetCursor(bv_, selendpar, selendpos);
332                         bv_->text->SetSelection(bv_);
333                         bv_->text->SetCursor(bv_, par, pos);
334                 } else {
335                         bv_->text->SetCursor(bv_, par, pos);
336                         bv_->text->sel_cursor = bv_->text->cursor;
337                         bv_->text->selection = false;
338                 }
339                 // remake the inset locking
340                 bv_->text->the_locking_inset = the_locking_inset;
341         }
342         bv_->text->first = screen_->TopCursorVisible(bv_->text);
343         buffer_->resizeInsets(bv_);
344         // this will scroll the screen such that the cursor becomes visible
345         updateScrollbar();
346         redraw();
347         owner_->getMiniBuffer()->Init();
348         bv_->setState();
349         AllowInput(bv_);
350
351         /// get rid of the splash screen if it's not gone already
352         owner_->getDialogs()->destroySplash();
353  
354         return 0;
355 }
356
357
358 void BufferView::Pimpl::updateScreen()
359 {
360         // Regenerate the screen.
361         screen_.reset(new LyXScreen(workarea_));
362         //delete screen_;
363         //screen_ = 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_->getMiniBuffer()->Set(inset->EditMessage());
638                 inset->InsetButtonPress(bv_, xpos, ypos, button);
639                 inset->Edit(bv_, xpos, ypos, button);
640                 return;
641         } 
642         
643         // Right click on a footnote flag opens float menu
644         if (button == 3) { 
645                 selection_possible = false;
646                 return;
647         }
648         
649         if (!inset_hit) // otherwise it was already set in checkInsetHit(...)
650                 bv_->text->SetCursorFromCoordinates(bv_, xpos, ypos + screen_first);
651         bv_->text->FinishUndo();
652         bv_->text->sel_cursor = bv_->text->cursor;
653         bv_->text->cursor.x_fix(bv_->text->cursor.x());
654         
655         owner_->updateLayoutChoice();
656         if (fitCursor(bv_->text)) {
657                 selection_possible = false;
658         }
659         
660         // Insert primary selection with middle mouse
661         // if there is a local selection in the current buffer,
662         // insert this
663         if (button == 2) {
664                 if (paste_internally)
665                         owner_->getLyXFunc()->Dispatch(LFUN_PASTE);
666                 else
667                         owner_->getLyXFunc()->Dispatch(LFUN_PASTESELECTION,
668                                                        "paragraph");
669                 selection_possible = false;
670                 return;
671         }
672 }
673
674
675 void BufferView::Pimpl::doubleClick(int /*x*/, int /*y*/, unsigned int button) 
676 {
677         // select a word
678         if (!buffer_)
679             return;
680
681         LyXText * text = bv_->getLyXText();
682
683         if (text->bv_owner && bv_->theLockingInset())
684             return;
685
686         if (screen_.get() && button == 1) {
687             if (text->bv_owner) {
688                 screen_->HideCursor();
689                 screen_->ToggleSelection(text, bv_);
690                 text->SelectWord(bv_);
691                 screen_->ToggleSelection(text, bv_, false);
692             } else {
693                 text->SelectWord(bv_);
694             }
695             /* This will fit the cursor on the screen
696              * if necessary */
697             update(text, BufferView::SELECT|BufferView::FITCUR);
698         }
699 }
700
701
702 void BufferView::Pimpl::tripleClick(int /*x*/, int /*y*/, unsigned int button)
703 {
704         // select a line
705         if (buffer_)
706                 return;
707
708         LyXText * text = bv_->getLyXText();
709
710         if (text->bv_owner && bv_->theLockingInset())
711             return;
712
713         if (screen_.get() && (button == 1)) {
714                 screen_->HideCursor();
715                 screen_->ToggleSelection(text, bv_);
716                 text->CursorHome(bv_);
717                 text->sel_cursor = text->cursor;
718                 text->CursorEnd(bv_);
719                 text->SetSelection(bv_);
720                 screen_->ToggleSelection(text, bv_, false);
721                 /* This will fit the cursor on the screen
722                  * if necessary */
723                 update(text, BufferView::SELECT|BufferView::FITCUR);
724         }
725 }
726
727
728 void BufferView::Pimpl::enterView()
729 {
730         if (active() && available()) {
731                 SetXtermCursor(workarea_.getWin());
732                 using_xterm_cursor = true;
733         }
734 }
735
736
737 void BufferView::Pimpl::leaveView()
738 {
739         if (using_xterm_cursor) {
740                 XUndefineCursor(fl_get_display(), workarea_.getWin());
741                 using_xterm_cursor = false;
742         }
743 }
744
745
746 void BufferView::Pimpl::workAreaButtonRelease(int x, int y,
747                                               unsigned int button)
748 {
749         if (!buffer_ || !screen_.get()) return;
750
751         // If we hit an inset, we have the inset coordinates in these
752         // and inset_hit points to the inset.  If we do not hit an
753         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
754         Inset * inset_hit = checkInsetHit(bv_->text, x, y, button);
755
756         if (bv_->theLockingInset()) {
757                 // We are in inset locking mode.
758
759                 /* LyX does a kind of work-area grabbing for insets.
760                    Only a ButtonPress Event outside the inset will 
761                    force a InsetUnlock. */
762                 bv_->theLockingInset()->
763                         InsetButtonRelease(bv_, x, y, button);
764                 return;
765         }
766         
767         selection_possible = false;
768         
769         if (button == 2)
770                 return;
771
772         bv_->setState();
773         owner_->showState();
774
775         // Did we hit an editable inset?
776         if (inset_hit) {
777                 // Inset like error, notes and figures
778                 selection_possible = false;
779
780                 // CHECK fix this proper in 0.13
781
782                 // Following a ref shouldn't issue
783                 // a push on the undo-stack
784                 // anylonger, now that we have
785                 // keybindings for following
786                 // references and returning from
787                 // references.  IMHO though, it
788                 // should be the inset's own business
789                 // to push or not push on the undo
790                 // stack. They don't *have* to
791                 // alter the document...
792                 // (Joacim)
793                 // ...or maybe the SetCursorParUndo()
794                 // below isn't necessary at all anylonger?
795                 if (inset_hit->LyxCode() == Inset::REF_CODE) {
796                         bv_->text->SetCursorParUndo(bv_->buffer());
797                 }
798
799                 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
800                 if (inset_hit->Editable()==Inset::HIGHLY_EDITABLE) {
801                         // Highly editable inset, like math
802                         UpdatableInset *inset = (UpdatableInset *)inset_hit;
803                         inset->InsetButtonRelease(bv_, x, y, button);
804                 } else {
805                         inset_hit->InsetButtonRelease(bv_, x, y, button);
806                         inset_hit->Edit(bv_, x, y, button);
807                 }
808                 return;
809         }
810
811 #ifndef NEW_INSETS
812         // check whether we want to open a float
813         if (bv_->text) {
814                 bool hit = false;
815                 char c = ' ';
816                 if (bv_->text->cursor.pos() <
817                     bv_->text->cursor.par()->Last()) {
818                         c = bv_->text->cursor.par()->
819                                 GetChar(bv_->text->cursor.pos());
820                 }
821                if(!bv_->text->selection)
822                 if (c == LyXParagraph::META_FOOTNOTE
823                     || c == LyXParagraph::META_MARGIN
824                     || c == LyXParagraph::META_FIG
825                     || c == LyXParagraph::META_TAB
826                     || c == LyXParagraph::META_WIDE_FIG
827                     || c == LyXParagraph::META_WIDE_TAB
828                     || c == LyXParagraph::META_ALGORITHM){
829                         hit = true;
830                 } else
831                         if (bv_->text->cursor.pos() - 1 >= 0) {
832                         c = bv_->text->cursor.par()->
833                                 GetChar(bv_->text->cursor.pos() - 1);
834                         if (c == LyXParagraph::META_FOOTNOTE
835                             || c == LyXParagraph::META_MARGIN
836                             || c == LyXParagraph::META_FIG
837                             || c == LyXParagraph::META_TAB
838                             || c == LyXParagraph::META_WIDE_FIG 
839                             || c == LyXParagraph::META_WIDE_TAB
840                             || c == LyXParagraph::META_ALGORITHM){
841                                 // We are one step too far to the right
842                                 bv_->text->CursorLeft(bv_);
843                                 hit = true;
844                         }
845                 }
846                 if (hit == true) {
847                         bv_->toggleFloat();
848                         selection_possible = false;
849                         return;
850                 }
851         }
852         // Do we want to close a float? (click on the float-label)
853         if (bv_->text->cursor.row()->par()->footnoteflag == 
854             LyXParagraph::OPEN_FOOTNOTE
855             && bv_->text->cursor.row()->previous() &&
856             bv_->text->cursor.row()->previous()->par()->
857             footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
858                 LyXFont font(LyXFont::ALL_SANE);
859                 font.setSize(LyXFont::SIZE_FOOTNOTE);
860
861                 int box_x = 20; // LYX_PAPER_MARGIN;
862                 box_x += lyxfont::width(" wide-tab ", font);
863
864                 unsigned int screen_first = bv_->text->first;
865
866                 if (x < box_x
867                     && y + screen_first > bv_->text->cursor.y() -
868                     bv_->text->cursor.row()->baseline()
869                     && y + screen_first < bv_->text->cursor.y() -
870                     bv_->text->cursor.row()->baseline()
871                     + lyxfont::maxAscent(font) * 1.2 + lyxfont::maxDescent(font) * 1.2) {
872                         bv_->toggleFloat();
873                         selection_possible = false;
874                         return;
875                 }
876         }
877 #else
878         // check whether we want to open a float
879         if (bv_->text) {
880                 bool hit = false;
881                 char c = ' ';
882                 if (bv_->text->cursor.pos() <
883                     bv_->text->cursor.par()->size()) {
884                         c = bv_->text->cursor.par()->
885                                 GetChar(bv_->text->cursor.pos());
886                 }
887                         if (bv_->text->cursor.pos() - 1 >= 0) {
888                         c = bv_->text->cursor.par()->
889                                 GetChar(bv_->text->cursor.pos() - 1);
890                 }
891                 if (hit == true) {
892                         selection_possible = false;
893                         return;
894                 }
895         }
896 #endif
897         // Maybe we want to edit a bibitem ale970302
898         if (bv_->text->cursor.par()->bibkey && x < 20 + 
899             bibitemMaxWidth(bv_, textclasslist.
900                             TextClass(buffer_->
901                                       params.textclass).defaultfont())) {
902                 bv_->text->cursor.par()->bibkey->Edit(bv_, 0, 0, 0);
903         }
904
905         return;
906 }
907
908
909 /* 
910  * Returns an inset if inset was hit. 0 otherwise.
911  * If hit, the coordinates are changed relative to the inset. 
912  * Otherwise coordinates are not changed, and false is returned.
913  */
914 Inset * BufferView::Pimpl::checkInsetHit(LyXText * text, int & x, int & y,
915                                          unsigned int /* button */)
916 {
917         if (!screen_.get())
918                 return 0;
919   
920         int y_tmp = y + text->first;
921   
922         LyXCursor cursor;
923         text->SetCursorFromCoordinates(bv_, cursor, x, y_tmp);
924         text->SetCursor(bv_, cursor, cursor.par(),cursor.pos(),true);
925
926
927 #ifndef NEW_INSETS
928         if (cursor.pos() < cursor.par()->Last()
929 #else
930         if (cursor.pos() < cursor.par()->size()
931 #endif
932             && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
933             && cursor.par()->GetInset(cursor.pos())
934             && cursor.par()->GetInset(cursor.pos())->Editable()) {
935
936                 // Check whether the inset really was hit
937                 Inset * tmpinset = cursor.par()->GetInset(cursor.pos());
938                 LyXFont font = text->GetFont(bv_->buffer(),
939                                                   cursor.par(), cursor.pos());
940                 int const width = tmpinset->width(bv_, font);
941                 int const inset_x = font.isVisibleRightToLeft()
942                         ? cursor.x() - width : cursor.x();
943                 int const start_x = inset_x + tmpinset->scroll();
944                 int const end_x = inset_x + width;
945
946                 if (x > start_x && x < end_x
947                     && y_tmp > cursor.y() - tmpinset->ascent(bv_, font)
948                     && y_tmp < cursor.y() + tmpinset->descent(bv_, font)) {
949                         text->SetCursor(bv_, cursor.par(),cursor.pos(), true);
950                         x = x - start_x;
951                         // The origin of an inset is on the baseline
952                         y = y_tmp - (text->cursor.y()); 
953                         return tmpinset;
954                 }
955         }
956
957         if ((cursor.pos() - 1 >= 0) &&
958             (cursor.par()->GetChar(cursor.pos()-1) == LyXParagraph::META_INSET) &&
959             (cursor.par()->GetInset(cursor.pos() - 1)) &&
960             (cursor.par()->GetInset(cursor.pos() - 1)->Editable())) {
961                 Inset * tmpinset = cursor.par()->GetInset(cursor.pos()-1);
962                 LyXFont font = text->GetFont(bv_->buffer(), cursor.par(),
963                                                   cursor.pos()-1);
964                 int const width = tmpinset->width(bv_, font);
965                 int const inset_x = font.isVisibleRightToLeft()
966                         ? cursor.x() : cursor.x() - width;
967                 int const start_x = inset_x + tmpinset->scroll();
968                 int const end_x = inset_x + width;
969
970                 if (x > start_x && x < end_x
971                     && y_tmp > cursor.y() - tmpinset->ascent(bv_, font)
972                     && y_tmp < cursor.y() + tmpinset->descent(bv_, font)) {
973 #if 0
974                         if (move_cursor && (tmpinset != bv_->theLockingInset()))
975 #endif
976                                 text->SetCursor(bv_, cursor.par(),cursor.pos()-1,true);
977                         x = x - start_x;
978                         // The origin of an inset is on the baseline
979                         y = y_tmp - (text->cursor.y()); 
980                         return tmpinset;
981                 }
982         }
983         return 0;
984 }
985
986
987 void BufferView::Pimpl::workAreaExpose()
988 {
989         static int work_area_width = 0;
990         static unsigned int work_area_height = 0;
991
992         bool const widthChange = workarea_.workWidth() != work_area_width;
993         bool const heightChange = workarea_.height() != work_area_height;
994
995         // update from work area
996         work_area_width = workarea_.workWidth();
997         work_area_height = workarea_.height();
998         if (buffer_ != 0) {
999                 if (widthChange) {
1000                         // All buffers need a resize
1001                         bufferlist.resize();
1002
1003                         // Remove all texts from the textcache
1004                         // This is not _really_ what we want to do. What
1005                         // we really want to do is to delete in textcache
1006                         // that does not have a BufferView with matching
1007                         // width, but as long as we have only one BufferView
1008                         // deleting all gives the same result.
1009                         if (lyxerr.debugging())
1010                                 textcache.show(lyxerr, "Expose delete all");
1011                         textcache.clear();
1012                 } else if (heightChange) {
1013                         // Rebuild image of current screen
1014                         updateScreen();
1015                         // fitCursor() ensures we don't jump back
1016                         // to the start of the document on vertical
1017                         // resize
1018                         fitCursor(bv_->text);
1019
1020                         // The main window size has changed, repaint most stuff
1021                         redraw();
1022                         // ...including the minibuffer
1023                         owner_->getMiniBuffer()->Init();
1024
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                 if (buffer_->isLyxClean()) {
1104                         buffer_->markDirty();
1105 #if 0
1106                         owner_->getMiniBuffer()->setTimer(4);
1107 #endif
1108                 } else {
1109                         buffer_->markDirty();
1110                 }
1111         }
1112 }
1113
1114
1115 // Callback for cursor timer
1116 void BufferView::Pimpl::cursorToggle()
1117 {
1118         // Quite a nice place for asyncron Inset updating, isn't it?
1119         // Actually no! This is run even if no buffer exist... so (Lgb)
1120         if (!buffer_) {
1121                 cursor_timeout.restart();
1122                 return;
1123         }
1124  
1125         int status = 1;
1126         int pid = waitpid(static_cast<pid_t>(0), &status, WNOHANG);
1127         if (pid == -1) // error find out what is wrong
1128                 ; // ignore it for now.
1129         else if (pid > 0)
1130                 sigchldhandler(pid, &status);
1131
1132         updatelist.update(bv_);
1133         
1134         if (!screen_.get()) {
1135                 cursor_timeout.restart();
1136                 return;
1137         }
1138
1139         if (!bv_->theLockingInset()) {
1140                 screen_->CursorToggle(bv_->text, bv_);
1141         } else {
1142                 bv_->theLockingInset()->ToggleInsetCursor(bv_);
1143         }
1144         
1145         cursor_timeout.restart();
1146 }
1147
1148
1149 void BufferView::Pimpl::cursorPrevious(LyXText * text)
1150 {
1151         if (!text->cursor.row()->previous())
1152                 return;
1153         
1154         int y = text->first;
1155         if (text->inset_owner)
1156                 y += bv_->text->first;
1157         Row * cursorrow = text->cursor.row();
1158         text->SetCursorFromCoordinates(bv_, bv_->text->cursor.x_fix(), y);
1159         bv_->text->FinishUndo();
1160         // This is to allow jumping over large insets
1161         if ((cursorrow == text->cursor.row()))
1162                 text->CursorUp(bv_);
1163         
1164         if (text->inset_owner ||
1165             text->cursor.row()->height() < workarea_.height())
1166                 screen_->Draw(bv_->text, bv_,
1167                               text->cursor.y()
1168                               - text->cursor.row()->baseline()
1169                               + text->cursor.row()->height()
1170                               - workarea_.height() + 1 );
1171         updateScrollbar();
1172 }
1173
1174
1175 void BufferView::Pimpl::cursorNext(LyXText * text)
1176 {
1177         if (!text->cursor.row()->next())
1178                 return;
1179         
1180         int y = text->first + workarea_.height();
1181 //      if (text->inset_owner)
1182 //              y += bv_->text->first;
1183         text->GetRowNearY(y);
1184     
1185         Row * cursorrow = text->cursor.row();
1186         text->SetCursorFromCoordinates(bv_, text->cursor.x_fix(), y); // + workarea_->height());
1187         bv_->text->FinishUndo();
1188         // This is to allow jumping over large insets
1189         if ((cursorrow == bv_->text->cursor.row()))
1190                 text->CursorDown(bv_);
1191         
1192         if (text->inset_owner ||
1193             text->cursor.row()->height() < workarea_.height())
1194                 screen_->Draw(bv_->text, bv_, text->cursor.y() -
1195                               text->cursor.row()->baseline());
1196         updateScrollbar();
1197 }
1198
1199
1200 bool BufferView::Pimpl::available() const
1201 {
1202         if (buffer_ && bv_->text) return true;
1203         return false;
1204 }
1205
1206
1207 void BufferView::Pimpl::beforeChange(LyXText * text)
1208 {
1209         toggleSelection();
1210         text->ClearSelection(bv_);
1211 }
1212
1213
1214 void BufferView::Pimpl::savePosition(unsigned int i)
1215 {
1216         if (i >= saved_positions_num)
1217                 return;
1218         saved_positions[i] = Position(buffer_->fileName(),
1219                                       bv_->text->cursor.par()->id(),
1220                                       bv_->text->cursor.pos());
1221         if (i > 0)
1222                 owner_->getMiniBuffer()->Set(_("Saved bookmark"), tostr(i));
1223 }
1224
1225
1226 void BufferView::Pimpl::restorePosition(unsigned int i)
1227 {
1228         if (i >= saved_positions_num)
1229                 return;
1230
1231         string fname = saved_positions[i].filename;
1232
1233         beforeChange(bv_->text);
1234
1235         if (fname != buffer_->fileName()) {
1236                 Buffer * b = bufferlist.exists(fname) ?
1237                         bufferlist.getBuffer(fname) :
1238                         bufferlist.loadLyXFile(fname); // don't ask, just load it
1239                 if (b != 0 ) buffer(b);
1240         }
1241
1242         LyXParagraph * par = bv_->text->GetParFromID(saved_positions[i].par_id);
1243         if (!par)
1244                 return;
1245
1246 #ifndef NEW_INSETS
1247         bv_->text->SetCursor(bv_, par,
1248                              min(par->Last(), saved_positions[i].par_pos));
1249 #else
1250         bv_->text->SetCursor(bv_, par,
1251                              min(par->size(), saved_positions[i].par_pos));
1252 #endif
1253         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1254         if (i > 0)
1255                 owner_->getMiniBuffer()->Set(_("Moved to bookmark"), tostr(i));
1256 }
1257
1258
1259 bool BufferView::Pimpl::isSavedPosition(unsigned int i)
1260 {
1261         if (i >= saved_positions_num)
1262                 return false;
1263
1264         return !saved_positions[i].filename.empty();
1265 }
1266
1267
1268 void BufferView::Pimpl::setState()
1269 {
1270         if (!lyxrc.rtl_support)
1271                 return;
1272
1273         LyXText * text = bv_->getLyXText();
1274         if (text->real_current_font.isRightToLeft() &&
1275             text->real_current_font.latex() != LyXFont::ON) {
1276                 if (owner_->getIntl()->keymap == Intl::PRIMARY)
1277                         owner_->getIntl()->KeyMapSec();
1278         } else {
1279                 if (owner_->getIntl()->keymap == Intl::SECONDARY)
1280                         owner_->getIntl()->KeyMapPrim();
1281         }
1282 }
1283
1284
1285 void BufferView::Pimpl::insetSleep()
1286 {
1287         if (bv_->theLockingInset() && !bv_->inset_slept) {
1288                 bv_->theLockingInset()->GetCursorPos(bv_, bv_->slx, bv_->sly);
1289                 bv_->theLockingInset()->InsetUnlock(bv_);
1290                 bv_->inset_slept = true;
1291         }
1292 }
1293
1294
1295 void BufferView::Pimpl::insetWakeup()
1296 {
1297         if (bv_->theLockingInset() && bv_->inset_slept) {
1298                 bv_->theLockingInset()->Edit(bv_, bv_->slx, bv_->sly, 0);
1299                 bv_->inset_slept = false;
1300         }
1301 }
1302
1303
1304 void BufferView::Pimpl::insetUnlock()
1305 {
1306         if (bv_->theLockingInset()) {
1307                 if (!bv_->inset_slept)
1308                         bv_->theLockingInset()->InsetUnlock(bv_);
1309                 bv_->theLockingInset(0);
1310                 bv_->text->FinishUndo();
1311                 bv_->inset_slept = false;
1312         }
1313 }
1314
1315
1316 bool BufferView::Pimpl::focus() const
1317 {
1318         return workarea_.hasFocus();
1319 }
1320
1321
1322 void BufferView::Pimpl::focus(bool f)
1323 {
1324         if (f) workarea_.setFocus();
1325 }
1326
1327
1328 bool BufferView::Pimpl::active() const
1329 {
1330         return workarea_.active();
1331 }
1332
1333
1334 bool BufferView::Pimpl::belowMouse() const 
1335 {
1336         return workarea_.belowMouse();
1337 }
1338
1339
1340 void BufferView::Pimpl::showCursor()
1341 {
1342         if (screen_.get())
1343                 screen_->ShowCursor(bv_->text, bv_);
1344 }
1345
1346
1347 void BufferView::Pimpl::hideCursor()
1348 {
1349         if (screen_.get())
1350                 screen_->HideCursor();
1351 }
1352
1353
1354 void BufferView::Pimpl::toggleSelection(bool b)
1355 {
1356         if (screen_.get())
1357                 screen_->ToggleSelection(bv_->text, bv_, b);
1358 }
1359
1360
1361 void BufferView::Pimpl::toggleToggle()
1362 {
1363         if (screen_.get())
1364                 screen_->ToggleToggle(bv_->text, bv_);
1365 }
1366
1367
1368 void BufferView::Pimpl::center() 
1369 {
1370         beforeChange(bv_->text);
1371         if (bv_->text->cursor.y() > static_cast<int>((workarea_.height() / 2))) {
1372                 screen_->Draw(bv_->text, bv_, bv_->text->cursor.y() - workarea_.height() / 2);
1373         } else {
1374                 screen_->Draw(bv_->text, bv_, 0);
1375         }
1376         update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1377         redraw();
1378 }
1379
1380
1381 void BufferView::Pimpl::pasteClipboard(bool asPara) 
1382 {
1383         if (!buffer_) return;
1384
1385         screen_->HideCursor();
1386         beforeChange(bv_->text);
1387         
1388         string const clip(workarea_.getClipboard());
1389         
1390         if (clip.empty()) return;
1391
1392         if (asPara) {
1393                 bv_->text->InsertStringB(bv_, clip);
1394         } else {
1395                 bv_->text->InsertStringA(bv_, clip);
1396         }
1397         update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1398 }
1399
1400
1401 void BufferView::Pimpl::stuffClipboard(string const & stuff) const
1402 {
1403         workarea_.putClipboard(stuff);
1404 }
1405
1406
1407 /*
1408  * Dispatch functions for actions which can be valid for BufferView->text
1409  * and/or InsetText->text!!!
1410  */
1411 static LyXText * TEXT(BufferView * bv) { return bv->getLyXText(); }
1412
1413 inline
1414 void BufferView::Pimpl::moveCursorUpdate(bool selecting)
1415 {
1416         if (selecting || TEXT(bv_)->mark_set) {
1417                 TEXT(bv_)->SetSelection(bv_);
1418                 if (TEXT(bv_)->bv_owner)
1419                         bv_->toggleToggle();
1420         }
1421         update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1422         showCursor();
1423         
1424         /* ---> Everytime the cursor is moved, show the current font state. */
1425         // should this too me moved out of this func?
1426         //owner->showState();
1427         bv_->setState();
1428 }
1429
1430
1431 Inset * BufferView::Pimpl::getInsetByCode(Inset::Code code)
1432 {
1433         LyXCursor cursor = TEXT(bv_)->cursor;
1434         Buffer::inset_iterator it =
1435                 find_if(Buffer::inset_iterator(
1436                         cursor.par(), cursor.pos()),
1437                         buffer_->inset_iterator_end(),
1438                         compare_memfun(&Inset::LyxCode, code)
1439                         );
1440         return it != buffer_->inset_iterator_end() ? (*it) : 0;
1441 }
1442
1443
1444 void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
1445 {
1446         string filename = filen;
1447
1448         if (filename.empty()) {
1449                 // Launch a file browser
1450                 string initpath = lyxrc.document_path;
1451
1452                 if (available()) {
1453                         string const trypath = owner_->buffer()->filepath;
1454                         // If directory is writeable, use this as default.
1455                         if (IsDirWriteable(trypath) == 1)
1456                                 initpath = trypath;
1457                 }
1458
1459                 FileDialog fileDlg(bv_->owner(), _("Select LyX document to insert"),
1460                         LFUN_FILE_INSERT,
1461                         make_pair(string(_("Documents")), string(lyxrc.document_path)),
1462                         make_pair(string(_("Examples")), string(AddPath(system_lyxdir, "examples"))));
1463
1464                 FileDialog::Result result = fileDlg.Select(initpath, _("*.lyx| LyX Documents (*.lyx)"));
1465  
1466                 if (result.first == FileDialog::Later)
1467                         return;
1468
1469                 filename = result.second;
1470
1471                 // check selected filename
1472                 if (filename.empty()) {
1473                         owner_->getMiniBuffer()->Set(_("Canceled."));
1474                         return;
1475                 }
1476         }
1477
1478         // get absolute path of file and make sure the filename ends
1479         // with .lyx
1480         filename = MakeAbsPath(filename);
1481         if (!IsLyXFilename(filename))
1482                 filename += ".lyx";
1483
1484         // Inserts document
1485         owner_->getMiniBuffer()->Set(_("Inserting document"),
1486                                      MakeDisplayPath(filename), "...");
1487         bool const res = bv_->insertLyXFile(filename);
1488         if (res) {
1489                 owner_->getMiniBuffer()->Set(_("Document"),
1490                                              MakeDisplayPath(filename),
1491                                              _("inserted."));
1492         } else {
1493                 owner_->getMiniBuffer()->Set(_("Could not insert document"),
1494                                              MakeDisplayPath(filename));
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 }