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