12 #include "BufferView_pimpl.h"
14 #include "lyxscreen.h"
18 #include "commandtags.h"
20 #include "bufferview_funcs.h"
21 #include "TextCache.h"
22 #include "bufferlist.h"
23 #include "lyx_gui_misc.h"
26 #include "support/LAssert.h"
27 #include "frontends/Dialogs.h"
28 #include "insets/insetbib.h"
29 #include "insets/insettext.h"
30 /// added for Dispatch functions
32 #include "frontends/FileDialog.h"
34 #include "FloatList.h"
35 #include "support/filetools.h"
36 #include "support/lyxfunctional.h"
37 #include "insets/inseturl.h"
38 #include "insets/insetlatexaccent.h"
39 #include "insets/insettoc.h"
40 #include "insets/insetref.h"
41 #include "insets/insetparent.h"
42 #include "insets/insetindex.h"
43 #include "insets/insetinfo.h"
44 #include "insets/insetinclude.h"
45 #include "insets/insetcite.h"
46 #include "insets/insetert.h"
47 #include "insets/insetexternal.h"
48 #include "insets/insetgraphics.h"
49 #include "insets/insetfoot.h"
50 #include "insets/insetmarginal.h"
51 #include "insets/insetminipage.h"
52 #include "insets/insetfloat.h"
53 #include "insets/insetlist.h"
54 #include "insets/insettabular.h"
55 #include "insets/insettheorem.h"
56 #include "insets/insetcaption.h"
57 #include "insets/insetfloatlist.h"
58 #include "mathed/formulamacro.h"
61 extern LyXTextClass::size_type current_layout;
62 extern int greek_kb_flag;
72 /* the selection possible is needed, that only motion events are
73 * used, where the bottom press event was on the drawing area too */
74 bool selection_possible = false;
76 extern BufferList bufferlist;
77 extern char ascii_type;
79 extern bool math_insert_greek(BufferView *, char);
80 extern void sigchldhandler(pid_t pid, int * status);
81 extern int bibitemMaxWidth(BufferView *, LyXFont const &);
83 const unsigned int saved_positions_num = 20;
90 XSync(fl_get_display(), 0);
94 void SetXtermCursor(Window win)
97 static bool cursor_undefined = true;
98 if (cursor_undefined){
99 cursor = XCreateFontCursor(fl_get_display(), XC_xterm);
100 XFlush(fl_get_display());
101 cursor_undefined = false;
103 XDefineCursor(fl_get_display(), win, cursor);
104 XFlush(fl_get_display());
110 BufferView::Pimpl::Pimpl(BufferView * b, LyXView * o,
111 int xpos, int ypos, int width, int height)
112 : bv_(b), owner_(o), buffer_(0),
113 current_scrollbar_value(0), cursor_timeout(400),
114 workarea_(xpos, ypos, width, height), using_xterm_cursor(false)
117 workarea_.scrollCB.connect(slot(this, &BufferView::Pimpl::scrollCB));
118 workarea_.workAreaExpose
119 .connect(slot(this, &BufferView::Pimpl::workAreaExpose));
120 workarea_.workAreaEnter
121 .connect(slot(this, &BufferView::Pimpl::enterView));
122 workarea_.workAreaLeave
123 .connect(slot(this, &BufferView::Pimpl::leaveView));
124 workarea_.workAreaButtonPress
125 .connect(slot(this, &BufferView::Pimpl::workAreaButtonPress));
126 workarea_.workAreaButtonRelease
128 &BufferView::Pimpl::workAreaButtonRelease));
129 workarea_.workAreaMotionNotify
130 .connect(slot(this, &BufferView::Pimpl::workAreaMotionNotify));
131 workarea_.workAreaDoubleClick
132 .connect(slot(this, &BufferView::Pimpl::doubleClick));
133 workarea_.workAreaTripleClick
134 .connect(slot(this, &BufferView::Pimpl::tripleClick));
135 workarea_.workAreaKeyPress
136 .connect(slot(this, &BufferView::Pimpl::workAreaKeyPress));
138 cursor_timeout.timeout.connect(slot(this,
139 &BufferView::Pimpl::cursorToggle));
140 //current_scrollbar_value = 0;
141 cursor_timeout.start();
142 workarea_.setFocus();
143 //using_xterm_cursor = false;
144 saved_positions.resize(saved_positions_num);
148 Painter & BufferView::Pimpl::painter()
150 return workarea_.getPainter();
154 void BufferView::Pimpl::buffer(Buffer * b)
156 lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
160 buffer_->delUser(bv_);
162 // Put the old text into the TextCache, but
163 // only if the buffer is still loaded.
164 // Also set the owner of the test to 0
165 // bv_->text->owner(0);
166 textcache.add(buffer_, workarea_.workWidth(), bv_->text);
167 if (lyxerr.debugging())
168 textcache.show(lyxerr, "BufferView::buffer");
173 // Set current buffer
176 if (bufferlist.getState() == BufferList::CLOSING) return;
179 // screen is always deleted when the buffer is changed.
182 // If we are closing the buffer, use the first buffer as current
184 buffer_ = bufferlist.first();
188 lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl;
189 buffer_->addUser(bv_);
190 // If we don't have a text object for this, we make one
191 if (bv_->text == 0) {
192 resizeCurrentBuffer();
197 bv_->text->first = screen_->TopCursorVisible(bv_->text);
198 owner_->updateMenubar();
199 owner_->updateToolbar();
200 // Similarly, buffer-dependent dialogs should be updated or
201 // hidden. This should go here because some dialogs (eg ToC)
202 // require bv_->text.
203 owner_->getDialogs()->updateBufferDependent(true);
207 lyxerr[Debug::INFO] << " No Buffer!" << endl;
208 owner_->updateMenubar();
209 owner_->updateToolbar();
210 owner_->getDialogs()->hideBufferDependent();
214 // Also remove all remaining text's from the testcache.
215 // (there should not be any!) (if there is any it is a
217 if (lyxerr.debugging())
218 textcache.show(lyxerr, "buffer delete all");
221 // should update layoutchoice even if we don't have a buffer.
222 owner_->updateLayoutChoice();
224 owner_->updateWindowTitle();
228 void BufferView::Pimpl::resize(int xpos, int ypos, int width, int height)
230 workarea_.resize(xpos, ypos, width, height);
231 update(bv_->text, SELECT);
236 void BufferView::Pimpl::resize()
239 resizeCurrentBuffer();
243 void BufferView::Pimpl::redraw()
245 lyxerr[Debug::INFO] << "BufferView::redraw()" << endl;
250 bool BufferView::Pimpl::fitCursor(LyXText * text)
252 lyx::Assert(screen_.get());
254 bool const ret = screen_->FitCursor(text, bv_);
261 void BufferView::Pimpl::redoCurrentBuffer()
263 lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
264 if (buffer_ && bv_->text) {
266 owner_->updateLayoutChoice();
271 int BufferView::Pimpl::resizeCurrentBuffer()
273 lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
275 LyXParagraph * par = 0;
276 LyXParagraph * selstartpar = 0;
277 LyXParagraph * selendpar = 0;
278 UpdatableInset * the_locking_inset = 0;
280 LyXParagraph::size_type pos = 0;
281 LyXParagraph::size_type selstartpos = 0;
282 LyXParagraph::size_type selendpos = 0;
283 bool selection = false;
284 bool mark_set = false;
288 owner_->message(_("Formatting document..."));
291 par = bv_->text->cursor.par();
292 pos = bv_->text->cursor.pos();
293 selstartpar = bv_->text->sel_start_cursor.par();
294 selstartpos = bv_->text->sel_start_cursor.pos();
295 selendpar = bv_->text->sel_end_cursor.par();
296 selendpos = bv_->text->sel_end_cursor.pos();
297 selection = bv_->text->selection;
298 mark_set = bv_->text->mark_set;
299 the_locking_inset = bv_->text->the_locking_inset;
301 bv_->text = new LyXText(bv_);
303 // See if we have a text in TextCache that fits
304 // the new buffer_ with the correct width.
305 bv_->text = textcache.findFit(buffer_, workarea_.workWidth());
307 if (lyxerr.debugging()) {
308 lyxerr << "Found a LyXText that fits:\n";
309 textcache.show(lyxerr, make_pair(buffer_, make_pair(workarea_.workWidth(), bv_->text)));
311 // Set the owner of the newly found text
312 // bv_->text->owner(bv_);
313 if (lyxerr.debugging())
314 textcache.show(lyxerr, "resizeCurrentBuffer");
316 bv_->text = new LyXText(bv_);
322 bv_->text->selection = true;
323 /* at this point just to avoid the Delete-Empty-Paragraph
324 * Mechanism when setting the cursor */
325 bv_->text->mark_set = mark_set;
327 bv_->text->SetCursor(bv_, selstartpar, selstartpos);
328 bv_->text->sel_cursor = bv_->text->cursor;
329 bv_->text->SetCursor(bv_, selendpar, selendpos);
330 bv_->text->SetSelection(bv_);
331 bv_->text->SetCursor(bv_, par, pos);
333 bv_->text->SetCursor(bv_, par, pos);
334 bv_->text->sel_cursor = bv_->text->cursor;
335 bv_->text->selection = false;
337 // remake the inset locking
338 bv_->text->the_locking_inset = the_locking_inset;
340 bv_->text->first = screen_->TopCursorVisible(bv_->text);
341 buffer_->resizeInsets(bv_);
342 // this will scroll the screen such that the cursor becomes visible
349 /// get rid of the splash screen if it's not gone already
350 owner_->getDialogs()->destroySplash();
356 void BufferView::Pimpl::updateScreen()
358 // Regenerate the screen.
359 screen_.reset(new LyXScreen(workarea_));
363 void BufferView::Pimpl::updateScrollbar()
365 /* If the text is smaller than the working area, the scrollbar
366 * maximum must be the working area height. No scrolling will
370 workarea_.setScrollbar(0, 1.0);
374 static unsigned long max2 = 0;
375 static unsigned long height2 = 0;
377 unsigned long cbth = 0;
381 cbth = bv_->text->height;
382 cbsf = bv_->text->first;
385 // check if anything has changed.
387 height2 == workarea_.height() &&
388 current_scrollbar_value == cbsf)
391 height2 = workarea_.height();
392 current_scrollbar_value = cbsf;
394 if (cbth <= height2) { // text is smaller than screen
395 workarea_.setScrollbar(0, 1.0); // right?
399 long maximum_height = workarea_.height() * 3 / 4 + cbth;
403 double hfloat = workarea_.height();
404 double maxfloat = maximum_height;
406 float slider_size = 0.0;
407 int slider_value = value;
409 workarea_.setScrollbarBounds(0, bv_->text->height - workarea_.height());
410 double const lineh = bv_->text->DefaultHeight();
411 workarea_.setScrollbarIncrements(lineh);
412 if (maxfloat > 0.0) {
413 if ((hfloat / maxfloat) * float(height2) < 3)
414 slider_size = 3.0/float(height2);
416 slider_size = hfloat / maxfloat;
418 slider_size = hfloat;
420 workarea_.setScrollbar(slider_value, slider_size / workarea_.height());
424 // Callback for scrollbar slider
425 void BufferView::Pimpl::scrollCB(double value)
427 if (!buffer_) return;
429 current_scrollbar_value = long(value);
430 if (current_scrollbar_value < 0)
431 current_scrollbar_value = 0;
436 screen_->Draw(bv_->text, bv_, current_scrollbar_value);
438 if (!lyxrc.cursor_follows_scrollbar) {
443 LyXText * vbt = bv_->text;
445 int const height = vbt->DefaultHeight();
446 int const first = static_cast<int>((bv_->text->first + height));
447 int const last = static_cast<int>((bv_->text->first + workarea_.height() - height));
449 if (vbt->cursor.y() < first)
450 vbt->SetCursorFromCoordinates(bv_, 0, first);
451 else if (vbt->cursor.y() > last)
452 vbt->SetCursorFromCoordinates(bv_, 0, last);
458 int BufferView::Pimpl::scrollUp(long time)
460 if (!buffer_) return 0;
461 if (!screen_.get()) return 0;
463 double value = workarea_.getScrollbarValue();
465 if (value == 0) return 0;
467 float add_value = (bv_->text->DefaultHeight()
468 + float(time) * float(time) * 0.125);
470 if (add_value > workarea_.height())
471 add_value = float(workarea_.height() -
472 bv_->text->DefaultHeight());
479 workarea_.setScrollbarValue(value);
486 int BufferView::Pimpl::scrollDown(long time)
488 if (!buffer_) return 0;
489 if (!screen_.get()) return 0;
491 double value = workarea_.getScrollbarValue();
492 pair<float, float> p = workarea_.getScrollbarBounds();
493 double max = p.second;
495 if (value == max) return 0;
497 float add_value = (bv_->text->DefaultHeight()
498 + float(time) * float(time) * 0.125);
500 if (add_value > workarea_.height())
501 add_value = float(workarea_.height() -
502 bv_->text->DefaultHeight());
509 workarea_.setScrollbarValue(value);
516 void BufferView::Pimpl::workAreaKeyPress(KeySym keysym, unsigned int state)
518 bv_->owner()->getLyXFunc()->processKeySym(keysym, state);
522 void BufferView::Pimpl::workAreaMotionNotify(int x, int y, unsigned int state)
524 // Only use motion with button 1
525 if (!(state & Button1MotionMask))
528 if (!buffer_ || !screen_.get()) return;
530 // Check for inset locking
531 if (bv_->theLockingInset()) {
532 LyXCursor cursor = bv_->text->cursor;
533 LyXFont font = bv_->text->GetFont(bv_->buffer(),
534 cursor.par(), cursor.pos());
535 int width = bv_->theLockingInset()->width(bv_, font);
536 int inset_x = font.isVisibleRightToLeft()
537 ? cursor.x() - width : cursor.x();
538 int start_x = inset_x + bv_->theLockingInset()->scroll();
539 bv_->theLockingInset()->
540 InsetMotionNotify(bv_,
542 y - cursor.y() + bv_->text->first,
547 /* The test for not selection possible is needed, that only motion events are
548 * used, where the bottom press event was on the drawing area too */
549 if (!selection_possible)
552 screen_->HideCursor();
554 bv_->text->SetCursorFromCoordinates(bv_, x, y + bv_->text->first);
556 if (!bv_->text->selection)
557 update(bv_->text, BufferView::UPDATE); // Maybe an empty line was deleted
559 bv_->text->SetSelection(bv_);
560 screen_->ToggleToggle(bv_->text, bv_);
561 fitCursor(bv_->text);
562 screen_->ShowCursor(bv_->text, bv_);
566 // Single-click on work area
567 void BufferView::Pimpl::workAreaButtonPress(int xpos, int ypos,
573 if (!buffer_ || !screen_.get()) return;
575 Inset * inset_hit = checkInsetHit(bv_->text, xpos, ypos, button);
577 // ok ok, this is a hack.
578 if (button == 4 || button == 5) {
581 scrollUp(lyxrc.wheel_jump); // default 100, set in lyxrc
584 scrollDown(lyxrc.wheel_jump);
589 if (bv_->theLockingInset()) {
590 // We are in inset locking mode
592 /* Check whether the inset was hit. If not reset mode,
593 otherwise give the event to the inset */
594 if (inset_hit == bv_->theLockingInset()) {
595 bv_->theLockingInset()->
596 InsetButtonPress(bv_,
601 bv_->unlockInset(bv_->theLockingInset());
606 selection_possible = true;
607 screen_->HideCursor();
609 int const screen_first = bv_->text->first;
611 // Middle button press pastes if we have a selection
612 bool paste_internally = false;
614 && bv_->text->selection) {
615 owner_->getLyXFunc()->Dispatch(LFUN_COPY);
616 paste_internally = true;
619 // Clear the selection
620 screen_->ToggleSelection(bv_->text, bv_);
621 bv_->text->ClearSelection(bv_);
622 bv_->text->FullRebreak(bv_);
623 screen_->Update(bv_->text, bv_);
626 // Single left click in math inset?
627 if ((inset_hit != 0) &&
628 (inset_hit->Editable()==Inset::HIGHLY_EDITABLE)) {
629 // Highly editable inset, like math
630 UpdatableInset * inset = static_cast<UpdatableInset *>(inset_hit);
631 selection_possible = false;
632 owner_->updateLayoutChoice();
633 owner_->message(inset->EditMessage());
634 inset->InsetButtonPress(bv_, xpos, ypos, button);
635 inset->Edit(bv_, xpos, ypos, button);
639 // Right click on a footnote flag opens float menu
641 selection_possible = false;
645 if (!inset_hit) // otherwise it was already set in checkInsetHit(...)
646 bv_->text->SetCursorFromCoordinates(bv_, xpos, ypos + screen_first);
647 bv_->text->FinishUndo();
648 bv_->text->sel_cursor = bv_->text->cursor;
649 bv_->text->cursor.x_fix(bv_->text->cursor.x());
651 owner_->updateLayoutChoice();
652 if (fitCursor(bv_->text)) {
653 selection_possible = false;
656 // Insert primary selection with middle mouse
657 // if there is a local selection in the current buffer,
660 if (paste_internally)
661 owner_->getLyXFunc()->Dispatch(LFUN_PASTE);
663 owner_->getLyXFunc()->Dispatch(LFUN_PASTESELECTION,
665 selection_possible = false;
671 void BufferView::Pimpl::doubleClick(int /*x*/, int /*y*/, unsigned int button)
677 LyXText * text = bv_->getLyXText();
679 if (text->bv_owner && bv_->theLockingInset())
682 if (screen_.get() && button == 1) {
683 if (text->bv_owner) {
684 screen_->HideCursor();
685 screen_->ToggleSelection(text, bv_);
686 text->SelectWord(bv_);
687 screen_->ToggleSelection(text, bv_, false);
689 text->SelectWord(bv_);
691 /* This will fit the cursor on the screen
693 update(text, BufferView::SELECT|BufferView::FITCUR);
698 void BufferView::Pimpl::tripleClick(int /*x*/, int /*y*/, unsigned int button)
704 LyXText * text = bv_->getLyXText();
706 if (text->bv_owner && bv_->theLockingInset())
709 if (screen_.get() && (button == 1)) {
710 screen_->HideCursor();
711 screen_->ToggleSelection(text, bv_);
712 text->CursorHome(bv_);
713 text->sel_cursor = text->cursor;
714 text->CursorEnd(bv_);
715 text->SetSelection(bv_);
716 screen_->ToggleSelection(text, bv_, false);
717 /* This will fit the cursor on the screen
719 update(text, BufferView::SELECT|BufferView::FITCUR);
724 void BufferView::Pimpl::enterView()
726 if (active() && available()) {
727 SetXtermCursor(workarea_.getWin());
728 using_xterm_cursor = true;
733 void BufferView::Pimpl::leaveView()
735 if (using_xterm_cursor) {
736 XUndefineCursor(fl_get_display(), workarea_.getWin());
737 using_xterm_cursor = false;
742 void BufferView::Pimpl::workAreaButtonRelease(int x, int y,
745 if (!buffer_ || !screen_.get()) return;
747 // If we hit an inset, we have the inset coordinates in these
748 // and inset_hit points to the inset. If we do not hit an
749 // inset, inset_hit is 0, and inset_x == x, inset_y == y.
750 Inset * inset_hit = checkInsetHit(bv_->text, x, y, button);
752 if (bv_->theLockingInset()) {
753 // We are in inset locking mode.
755 /* LyX does a kind of work-area grabbing for insets.
756 Only a ButtonPress Event outside the inset will
757 force a InsetUnlock. */
758 bv_->theLockingInset()->
759 InsetButtonRelease(bv_, x, y, button);
763 selection_possible = false;
771 // Did we hit an editable inset?
773 // Inset like error, notes and figures
774 selection_possible = false;
776 // CHECK fix this proper in 0.13
778 // Following a ref shouldn't issue
779 // a push on the undo-stack
780 // anylonger, now that we have
781 // keybindings for following
782 // references and returning from
783 // references. IMHO though, it
784 // should be the inset's own business
785 // to push or not push on the undo
786 // stack. They don't *have* to
787 // alter the document...
789 // ...or maybe the SetCursorParUndo()
790 // below isn't necessary at all anylonger?
791 if (inset_hit->LyxCode() == Inset::REF_CODE) {
792 bv_->text->SetCursorParUndo(bv_->buffer());
795 owner_->message(inset_hit->EditMessage());
797 if (inset_hit->Editable()==Inset::HIGHLY_EDITABLE) {
798 // Highly editable inset, like math
799 UpdatableInset *inset = (UpdatableInset *)inset_hit;
800 inset->InsetButtonRelease(bv_, x, y, button);
802 inset_hit->InsetButtonRelease(bv_, x, y, button);
803 inset_hit->Edit(bv_, x, y, button);
808 // check whether we want to open a float
812 if (bv_->text->cursor.pos() <
813 bv_->text->cursor.par()->size()) {
814 c = bv_->text->cursor.par()->
815 GetChar(bv_->text->cursor.pos());
817 if (bv_->text->cursor.pos() - 1 >= 0) {
818 c = bv_->text->cursor.par()->
819 GetChar(bv_->text->cursor.pos() - 1);
822 selection_possible = false;
827 // Maybe we want to edit a bibitem ale970302
828 if (bv_->text->cursor.par()->bibkey && x < 20 +
829 bibitemMaxWidth(bv_, textclasslist.
831 params.textclass).defaultfont())) {
832 bv_->text->cursor.par()->bibkey->Edit(bv_, 0, 0, 0);
840 * Returns an inset if inset was hit. 0 otherwise.
841 * If hit, the coordinates are changed relative to the inset.
842 * Otherwise coordinates are not changed, and false is returned.
844 Inset * BufferView::Pimpl::checkInsetHit(LyXText * text, int & x, int & y,
845 unsigned int /* button */)
850 int y_tmp = y + text->first;
853 text->SetCursorFromCoordinates(bv_, cursor, x, y_tmp);
854 text->SetCursor(bv_, cursor, cursor.par(),cursor.pos(),true);
857 if (cursor.pos() < cursor.par()->size()
858 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
859 && cursor.par()->GetInset(cursor.pos())
860 && cursor.par()->GetInset(cursor.pos())->Editable()) {
862 // Check whether the inset really was hit
863 Inset * tmpinset = cursor.par()->GetInset(cursor.pos());
864 LyXFont font = text->GetFont(bv_->buffer(),
865 cursor.par(), cursor.pos());
866 int const width = tmpinset->width(bv_, font);
867 int const inset_x = font.isVisibleRightToLeft()
868 ? cursor.x() - width : cursor.x();
869 int const start_x = inset_x + tmpinset->scroll();
870 int const end_x = inset_x + width;
872 if (x > start_x && x < end_x
873 && y_tmp > cursor.y() - tmpinset->ascent(bv_, font)
874 && y_tmp < cursor.y() + tmpinset->descent(bv_, font)) {
875 text->SetCursor(bv_, cursor.par(),cursor.pos(), true);
877 // The origin of an inset is on the baseline
878 y = y_tmp - (text->cursor.y());
883 if ((cursor.pos() - 1 >= 0) &&
884 (cursor.par()->GetChar(cursor.pos()-1) == LyXParagraph::META_INSET) &&
885 (cursor.par()->GetInset(cursor.pos() - 1)) &&
886 (cursor.par()->GetInset(cursor.pos() - 1)->Editable())) {
887 Inset * tmpinset = cursor.par()->GetInset(cursor.pos()-1);
888 LyXFont font = text->GetFont(bv_->buffer(), cursor.par(),
890 int const width = tmpinset->width(bv_, font);
891 int const inset_x = font.isVisibleRightToLeft()
892 ? cursor.x() : cursor.x() - width;
893 int const start_x = inset_x + tmpinset->scroll();
894 int const end_x = inset_x + width;
896 if (x > start_x && x < end_x
897 && y_tmp > cursor.y() - tmpinset->ascent(bv_, font)
898 && y_tmp < cursor.y() + tmpinset->descent(bv_, font)) {
900 if (move_cursor && (tmpinset != bv_->theLockingInset()))
902 text->SetCursor(bv_, cursor.par(),
903 cursor.pos() - 1, true);
905 // The origin of an inset is on the baseline
906 y = y_tmp - (text->cursor.y());
914 void BufferView::Pimpl::workAreaExpose()
916 static int work_area_width = 0;
917 static unsigned int work_area_height = 0;
919 bool const widthChange = workarea_.workWidth() != work_area_width;
920 bool const heightChange = workarea_.height() != work_area_height;
922 // update from work area
923 work_area_width = workarea_.workWidth();
924 work_area_height = workarea_.height();
927 // All buffers need a resize
930 // Remove all texts from the textcache
931 // This is not _really_ what we want to do. What
932 // we really want to do is to delete in textcache
933 // that does not have a BufferView with matching
934 // width, but as long as we have only one BufferView
935 // deleting all gives the same result.
936 if (lyxerr.debugging())
937 textcache.show(lyxerr, "Expose delete all");
939 } else if (heightChange) {
940 // Rebuild image of current screen
942 // fitCursor() ensures we don't jump back
943 // to the start of the document on vertical
945 fitCursor(bv_->text);
947 // The main window size has changed, repaint most stuff
949 } else if (screen_.get())
950 screen_->Redraw(bv_->text, bv_);
952 // Grey box when we don't have a buffer
956 // always make sure that the scrollbar is sane.
958 owner_->updateLayoutChoice();
963 void BufferView::Pimpl::update()
965 if (screen_.get()) screen_->Update(bv_->text, bv_);
968 // Values used when calling update:
970 // -2 - update, move sel_cursor if selection, fitcursor
971 // -1 - update, move sel_cursor if selection, fitcursor, mark dirty
972 // 0 - update, move sel_cursor if selection, fitcursor
973 // 1 - update, move sel_cursor if selection, fitcursor, mark dirty
974 // 3 - update, move sel_cursor if selection
977 // a simple redraw of the parts that need refresh
979 // move sel_cursor if selection -
980 // the text's sel_cursor is moved if there is selection is progress
983 // fitCursor() is called and the scrollbar updated
986 // the buffer is marked dirty.
995 // UPDATE_ONLY = UPDATE;
996 // UPDATE_SELECT = UPDATE | SELECT;
997 // UPDATE_SELECT_MOVE = UPDATE | SELECT | FITCUR;
998 // UPDATE_SELECT_MOVE_AFTER_CHANGE = UPDATE | SELECT | FITCUR | CHANGE;
1000 // update(-3) -> update(0) -> update(0) -> update(UPDATE)
1001 // update(-2) -> update(1 + 2) -> update(3) -> update(SELECT|FITCUR)
1002 // update(-1) -> update(1 + 2 + 4) -> update(7) -> update(SELECT|FITCUR|CHANGE)
1003 // update(1) -> update(1 + 2 + 4) -> update(7) -> update(SELECT|FITCUR|CHANGE)
1004 // update(3) -> update(1) -> update(1) -> update(SELECT)
1006 void BufferView::Pimpl::update(LyXText * text, BufferView::UpdateCodes f)
1008 owner_->updateLayoutChoice();
1010 if (!text->selection && (f & SELECT)) {
1011 text->sel_cursor = text->cursor;
1014 text->FullRebreak(bv_);
1016 if (text->inset_owner) {
1017 text->inset_owner->SetUpdateStatus(bv_, InsetText::NONE);
1018 bv_->updateInset(text->inset_owner, true);
1027 buffer_->markDirty();
1032 // Callback for cursor timer
1033 void BufferView::Pimpl::cursorToggle()
1035 // Quite a nice place for asyncron Inset updating, isn't it?
1036 // Actually no! This is run even if no buffer exist... so (Lgb)
1038 cursor_timeout.restart();
1043 int pid = waitpid(static_cast<pid_t>(0), &status, WNOHANG);
1044 if (pid == -1) // error find out what is wrong
1045 ; // ignore it for now.
1047 sigchldhandler(pid, &status);
1049 updatelist.update(bv_);
1051 if (!screen_.get()) {
1052 cursor_timeout.restart();
1056 if (!bv_->theLockingInset()) {
1057 screen_->CursorToggle(bv_->text, bv_);
1059 bv_->theLockingInset()->ToggleInsetCursor(bv_);
1062 cursor_timeout.restart();
1066 void BufferView::Pimpl::cursorPrevious(LyXText * text)
1068 if (!text->cursor.row()->previous())
1071 int y = text->first;
1072 if (text->inset_owner)
1073 y += bv_->text->first;
1074 Row * cursorrow = text->cursor.row();
1075 text->SetCursorFromCoordinates(bv_, bv_->text->cursor.x_fix(), y);
1076 bv_->text->FinishUndo();
1077 // This is to allow jumping over large insets
1078 if ((cursorrow == text->cursor.row()))
1079 text->CursorUp(bv_);
1081 if (text->inset_owner ||
1082 text->cursor.row()->height() < workarea_.height())
1083 screen_->Draw(bv_->text, bv_,
1085 - text->cursor.row()->baseline()
1086 + text->cursor.row()->height()
1087 - workarea_.height() + 1 );
1092 void BufferView::Pimpl::cursorNext(LyXText * text)
1094 if (!text->cursor.row()->next())
1097 int y = text->first + workarea_.height();
1098 // if (text->inset_owner)
1099 // y += bv_->text->first;
1100 text->GetRowNearY(y);
1102 Row * cursorrow = text->cursor.row();
1103 text->SetCursorFromCoordinates(bv_, text->cursor.x_fix(), y); // + workarea_->height());
1104 bv_->text->FinishUndo();
1105 // This is to allow jumping over large insets
1106 if ((cursorrow == bv_->text->cursor.row()))
1107 text->CursorDown(bv_);
1109 if (text->inset_owner ||
1110 text->cursor.row()->height() < workarea_.height())
1111 screen_->Draw(bv_->text, bv_, text->cursor.y() -
1112 text->cursor.row()->baseline());
1117 bool BufferView::Pimpl::available() const
1119 if (buffer_ && bv_->text) return true;
1124 void BufferView::Pimpl::beforeChange(LyXText * text)
1127 text->ClearSelection(bv_);
1131 void BufferView::Pimpl::savePosition(unsigned int i)
1133 if (i >= saved_positions_num)
1135 saved_positions[i] = Position(buffer_->fileName(),
1136 bv_->text->cursor.par()->id(),
1137 bv_->text->cursor.pos());
1139 string const str = _("Saved bookmark") + ' ' + tostr(i);
1140 owner_->message(str);
1145 void BufferView::Pimpl::restorePosition(unsigned int i)
1147 if (i >= saved_positions_num)
1150 string const fname = saved_positions[i].filename;
1152 beforeChange(bv_->text);
1154 if (fname != buffer_->fileName()) {
1155 Buffer * b = bufferlist.exists(fname) ?
1156 bufferlist.getBuffer(fname) :
1157 bufferlist.loadLyXFile(fname); // don't ask, just load it
1158 if (b != 0 ) buffer(b);
1161 LyXParagraph * par = bv_->text->GetParFromID(saved_positions[i].par_id);
1165 bv_->text->SetCursor(bv_, par,
1166 min(par->size(), saved_positions[i].par_pos));
1168 update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1170 string const str = _("Moved to bookmark") + ' ' + tostr(i);
1171 owner_->message(str);
1176 bool BufferView::Pimpl::isSavedPosition(unsigned int i)
1178 if (i >= saved_positions_num)
1181 return !saved_positions[i].filename.empty();
1185 void BufferView::Pimpl::setState()
1187 if (!lyxrc.rtl_support)
1190 LyXText * text = bv_->getLyXText();
1191 if (text->real_current_font.isRightToLeft() &&
1192 text->real_current_font.latex() != LyXFont::ON) {
1193 if (owner_->getIntl()->keymap == Intl::PRIMARY)
1194 owner_->getIntl()->KeyMapSec();
1196 if (owner_->getIntl()->keymap == Intl::SECONDARY)
1197 owner_->getIntl()->KeyMapPrim();
1202 void BufferView::Pimpl::insetSleep()
1204 if (bv_->theLockingInset() && !bv_->inset_slept) {
1205 bv_->theLockingInset()->GetCursorPos(bv_, bv_->slx, bv_->sly);
1206 bv_->theLockingInset()->InsetUnlock(bv_);
1207 bv_->inset_slept = true;
1212 void BufferView::Pimpl::insetWakeup()
1214 if (bv_->theLockingInset() && bv_->inset_slept) {
1215 bv_->theLockingInset()->Edit(bv_, bv_->slx, bv_->sly, 0);
1216 bv_->inset_slept = false;
1221 void BufferView::Pimpl::insetUnlock()
1223 if (bv_->theLockingInset()) {
1224 if (!bv_->inset_slept)
1225 bv_->theLockingInset()->InsetUnlock(bv_);
1226 bv_->theLockingInset(0);
1227 bv_->text->FinishUndo();
1228 bv_->inset_slept = false;
1233 bool BufferView::Pimpl::focus() const
1235 return workarea_.hasFocus();
1239 void BufferView::Pimpl::focus(bool f)
1241 if (f) workarea_.setFocus();
1245 bool BufferView::Pimpl::active() const
1247 return workarea_.active();
1251 bool BufferView::Pimpl::belowMouse() const
1253 return workarea_.belowMouse();
1257 void BufferView::Pimpl::showCursor()
1260 screen_->ShowCursor(bv_->text, bv_);
1264 void BufferView::Pimpl::hideCursor()
1267 screen_->HideCursor();
1271 void BufferView::Pimpl::toggleSelection(bool b)
1274 screen_->ToggleSelection(bv_->text, bv_, b);
1278 void BufferView::Pimpl::toggleToggle()
1281 screen_->ToggleToggle(bv_->text, bv_);
1285 void BufferView::Pimpl::center()
1287 beforeChange(bv_->text);
1288 if (bv_->text->cursor.y() > static_cast<int>((workarea_.height() / 2))) {
1289 screen_->Draw(bv_->text, bv_, bv_->text->cursor.y() - workarea_.height() / 2);
1291 screen_->Draw(bv_->text, bv_, 0);
1293 update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1298 void BufferView::Pimpl::pasteClipboard(bool asPara)
1300 if (!buffer_) return;
1302 screen_->HideCursor();
1303 beforeChange(bv_->text);
1305 string const clip(workarea_.getClipboard());
1307 if (clip.empty()) return;
1310 bv_->text->InsertStringB(bv_, clip);
1312 bv_->text->InsertStringA(bv_, clip);
1314 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1318 void BufferView::Pimpl::stuffClipboard(string const & stuff) const
1320 workarea_.putClipboard(stuff);
1325 * Dispatch functions for actions which can be valid for BufferView->text
1326 * and/or InsetText->text!!!
1328 static LyXText * TEXT(BufferView * bv) { return bv->getLyXText(); }
1331 void BufferView::Pimpl::moveCursorUpdate(bool selecting)
1333 if (selecting || TEXT(bv_)->mark_set) {
1334 TEXT(bv_)->SetSelection(bv_);
1335 if (TEXT(bv_)->bv_owner)
1336 bv_->toggleToggle();
1338 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1341 /* ---> Everytime the cursor is moved, show the current font state. */
1342 // should this too me moved out of this func?
1343 //owner->showState();
1348 Inset * BufferView::Pimpl::getInsetByCode(Inset::Code code)
1350 LyXCursor cursor = TEXT(bv_)->cursor;
1351 Buffer::inset_iterator it =
1352 find_if(Buffer::inset_iterator(
1353 cursor.par(), cursor.pos()),
1354 buffer_->inset_iterator_end(),
1355 lyx::compare_memfun(&Inset::LyxCode, code)
1357 return it != buffer_->inset_iterator_end() ? (*it) : 0;
1361 void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
1363 string filename = filen;
1365 if (filename.empty()) {
1366 // Launch a file browser
1367 string initpath = lyxrc.document_path;
1370 string const trypath = owner_->buffer()->filepath;
1371 // If directory is writeable, use this as default.
1372 if (IsDirWriteable(trypath) == 1)
1376 FileDialog fileDlg(bv_->owner(), _("Select LyX document to insert"),
1378 make_pair(string(_("Documents")), string(lyxrc.document_path)),
1379 make_pair(string(_("Examples")), string(AddPath(system_lyxdir, "examples"))));
1381 FileDialog::Result result = fileDlg.Select(initpath, _("*.lyx| LyX Documents (*.lyx)"));
1383 if (result.first == FileDialog::Later)
1386 filename = result.second;
1388 // check selected filename
1389 if (filename.empty()) {
1390 owner_->message(_("Canceled."));
1395 // get absolute path of file and make sure the filename ends
1397 filename = MakeAbsPath(filename);
1398 if (!IsLyXFilename(filename))
1402 string const s1 = _("Inserting document") + ' '
1403 + MakeDisplayPath(filename) + " ...";
1404 owner_->message(s1);
1405 bool const res = bv_->insertLyXFile(filename);
1407 string const str = _("Document") + ' '
1408 + MakeDisplayPath(filename) + ' ' + _("inserted.");
1409 owner_->message(str);
1411 string const str = _("Could not insert document") + ' '
1412 + MakeDisplayPath(filename);
1413 owner_->message(str);
1418 bool BufferView::Pimpl::Dispatch(kb_action action, string const & argument)
1421 // --- Misc -------------------------------------------
1424 TEXT(bv_)->toggleAppendix(bv_);
1425 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1429 case LFUN_TOC_INSERT:
1431 InsetCommandParams p;
1432 p.setCmdName("tableofcontents");
1433 Inset * inset = new InsetTOC(p);
1434 if (!bv_->insertInset(inset, "Standard", true))
1439 case LFUN_TABULAR_FEATURE:
1440 case LFUN_SCROLL_INSET:
1441 // this is not handled here as this funktion is only aktive
1442 // if we have a locking_inset and that one is (or contains)
1446 case LFUN_INSET_GRAPHICS:
1448 Inset * new_inset = new InsetGraphics;
1449 if (!bv_->insertInset(new_inset)) {
1452 // this is need because you don't use a inset->Edit()
1453 bv_->updateInset(new_inset, true);
1454 new_inset->Edit(bv_, 0, 0, 0);
1464 case LFUN_PASTESELECTION:
1466 bool asPara = false;
1467 if (argument == "paragraph") asPara = true;
1468 pasteClipboard(asPara);
1480 case LFUN_LAYOUT_COPY:
1481 bv_->copyEnvironment();
1484 case LFUN_LAYOUT_PASTE:
1485 bv_->pasteEnvironment();
1489 case LFUN_GOTOERROR:
1490 bv_->gotoInset(Inset::ERROR_CODE, false);
1494 bv_->gotoInset(Inset::IGNORE_CODE, false);
1497 case LFUN_REFERENCE_GOTO:
1499 vector<Inset::Code> tmp;
1500 tmp.push_back(Inset::LABEL_CODE);
1501 tmp.push_back(Inset::REF_CODE);
1502 bv_->gotoInset(tmp, true);
1506 case LFUN_HYPHENATION:
1507 bv_->hyphenationPoint();
1514 case LFUN_END_OF_SENTENCE:
1515 bv_->endOfSentenceDot();
1518 case LFUN_MENU_SEPARATOR:
1519 bv_->menuSeparator();
1527 changeDepth(bv_, TEXT(bv_), 0);
1530 case LFUN_DEPTH_MIN:
1531 changeDepth(bv_, TEXT(bv_), -1);
1534 case LFUN_DEPTH_PLUS:
1535 changeDepth(bv_, TEXT(bv_), 1);
1539 owner_->getDialogs()->setUserFreeFont();
1545 owner_->showState();
1548 case LFUN_FILE_INSERT:
1550 MenuInsertLyXFile(argument);
1554 case LFUN_FILE_INSERT_ASCII_PARA:
1555 InsertAsciiFile(bv_, argument, true);
1558 case LFUN_FILE_INSERT_ASCII:
1559 InsertAsciiFile(bv_, argument, false);
1564 lyxerr.debug() << "LFUN_LAYOUT: (arg) "
1565 << argument << endl;
1567 // Derive layout number from given argument (string)
1568 // and current buffer's textclass (number). */
1569 LyXTextClassList::ClassList::size_type tclass =
1570 buffer_->params.textclass;
1571 pair <bool, LyXTextClass::size_type> layout =
1572 textclasslist.NumberOfLayout(tclass, argument);
1574 // If the entry is obsolete, use the new one instead.
1576 string obs = textclasslist.Style(tclass,layout.second)
1580 textclasslist.NumberOfLayout(tclass, obs);
1583 // see if we found the layout number:
1584 if (!layout.first) {
1585 owner_->getLyXFunc()->setErrorMessage(
1586 string(N_("Layout ")) + argument +
1591 if (current_layout != layout.second) {
1593 current_layout = layout.second;
1595 BufferView::SELECT|BufferView::FITCUR);
1596 TEXT(bv_)->SetLayout(bv_, layout.second);
1597 owner_->setLayout(layout.second);
1599 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1606 Lang(bv_, argument);
1608 owner_->showState();
1613 owner_->showState();
1618 owner_->showState();
1623 owner_->showState();
1628 owner_->showState();
1633 owner_->showState();
1638 owner_->showState();
1643 owner_->showState();
1646 case LFUN_UNDERLINE:
1648 owner_->showState();
1651 case LFUN_FONT_SIZE:
1652 FontSize(bv_, argument);
1653 owner_->showState();
1656 case LFUN_FONT_STATE:
1657 owner_->getLyXFunc()->setMessage(CurrentState(bv_));
1660 case LFUN_UPCASE_WORD:
1661 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1662 TEXT(bv_)->ChangeWordCase(bv_, LyXText::text_uppercase);
1663 if (TEXT(bv_)->inset_owner)
1664 bv_->updateInset(TEXT(bv_)->inset_owner, true);
1665 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1668 case LFUN_LOWCASE_WORD:
1669 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1670 TEXT(bv_)->ChangeWordCase(bv_, LyXText::text_lowercase);
1671 if (TEXT(bv_)->inset_owner)
1672 bv_->updateInset(TEXT(bv_)->inset_owner, true);
1673 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1676 case LFUN_CAPITALIZE_WORD:
1677 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1678 TEXT(bv_)->ChangeWordCase(bv_,
1679 LyXText::text_capitalization);
1680 if (TEXT(bv_)->inset_owner)
1681 bv_->updateInset(TEXT(bv_)->inset_owner, true);
1682 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1685 case LFUN_TRANSPOSE_CHARS:
1686 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1687 TEXT(bv_)->TransposeChars(*bv_);
1688 if (TEXT(bv_)->inset_owner)
1689 bv_->updateInset(TEXT(bv_)->inset_owner, true);
1690 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1694 case LFUN_INSERT_LABEL:
1695 MenuInsertLabel(bv_, argument);
1698 case LFUN_REF_INSERT:
1699 if (argument.empty()) {
1700 InsetCommandParams p("ref");
1701 owner_->getDialogs()->createRef(p.getAsString());
1703 InsetCommandParams p;
1704 p.setFromString(argument);
1706 InsetRef * inset = new InsetRef(p, *buffer_);
1707 if (!bv_->insertInset(inset))
1710 bv_->updateInset(inset, true);
1714 case LFUN_BOOKMARK_SAVE:
1715 savePosition(strToUnsignedInt(argument));
1718 case LFUN_BOOKMARK_GOTO:
1719 restorePosition(strToUnsignedInt(argument));
1724 string label(argument);
1725 if (label.empty()) {
1727 static_cast<InsetRef*>(getInsetByCode(Inset::REF_CODE));
1729 label = inset->getContents();
1734 if (!label.empty()) {
1735 //bv_->savePosition(0);
1736 if (!bv_->gotoLabel(label))
1737 WriteAlert(_("Error"),
1738 _("Couldn't find this label"),
1739 _("in current document."));
1744 // --- Cursor Movements -----------------------------
1747 bool is_rtl = TEXT(bv_)->cursor.par()->isRightToLeftPar(buffer_->params);
1748 if (!TEXT(bv_)->mark_set)
1749 beforeChange(TEXT(bv_));
1750 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1752 TEXT(bv_)->CursorLeft(bv_, false);
1753 if (TEXT(bv_)->cursor.pos() < TEXT(bv_)->cursor.par()->size()
1754 && TEXT(bv_)->cursor.par()->GetChar(TEXT(bv_)->cursor.pos())
1755 == LyXParagraph::META_INSET
1756 && TEXT(bv_)->cursor.par()->GetInset(TEXT(bv_)->cursor.pos())
1757 && TEXT(bv_)->cursor.par()->GetInset(TEXT(bv_)->cursor.pos())->Editable() == Inset::HIGHLY_EDITABLE){
1758 Inset * tmpinset = TEXT(bv_)->cursor.par()->GetInset(TEXT(bv_)->cursor.pos());
1759 owner_->getLyXFunc()->setMessage(tmpinset->EditMessage());
1762 LyXFont const font =
1763 TEXT(bv_)->GetFont(buffer_,
1764 TEXT(bv_)->cursor.par(),
1765 TEXT(bv_)->cursor.pos());
1766 y = tmpinset->descent(bv_,font);
1768 tmpinset->Edit(bv_, 0, y, 0);
1772 TEXT(bv_)->CursorRight(bv_, false);
1773 TEXT(bv_)->FinishUndo();
1774 moveCursorUpdate(false);
1775 owner_->showState();
1781 // This is soooo ugly. Isn`t it possible to make
1782 // it simpler? (Lgb)
1783 bool is_rtl = TEXT(bv_)->cursor.par()->isRightToLeftPar(buffer_->params);
1784 if (!TEXT(bv_)->mark_set)
1785 beforeChange(TEXT(bv_));
1786 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1787 LyXCursor cur = TEXT(bv_)->cursor;
1789 TEXT(bv_)->CursorLeft(bv_, false);
1790 if ((is_rtl || cur != TEXT(bv_)->cursor) && // only if really moved!
1791 TEXT(bv_)->cursor.pos() < TEXT(bv_)->cursor.par()->size() &&
1792 (TEXT(bv_)->cursor.par()->GetChar(TEXT(bv_)->cursor.pos()) ==
1793 LyXParagraph::META_INSET) &&
1794 TEXT(bv_)->cursor.par()->GetInset(TEXT(bv_)->cursor.pos()) &&
1795 (TEXT(bv_)->cursor.par()->GetInset(TEXT(bv_)->cursor.pos())->Editable()
1796 == Inset::HIGHLY_EDITABLE))
1798 Inset * tmpinset = TEXT(bv_)->cursor.par()->GetInset(TEXT(bv_)->cursor.pos());
1799 owner_->getLyXFunc()->setMessage(tmpinset->EditMessage());
1800 LyXFont font = TEXT(bv_)->GetFont(buffer_,
1801 TEXT(bv_)->cursor.par(),
1802 TEXT(bv_)->cursor.pos());
1804 : tmpinset->descent(bv_,font);
1807 tmpinset->width(bv_,font),
1812 TEXT(bv_)->CursorRight(bv_, false);
1814 TEXT(bv_)->FinishUndo();
1815 moveCursorUpdate(false);
1816 owner_->showState();
1821 if (!TEXT(bv_)->mark_set)
1822 beforeChange(TEXT(bv_));
1823 update(TEXT(bv_), BufferView::UPDATE);
1824 TEXT(bv_)->CursorUp(bv_);
1825 TEXT(bv_)->FinishUndo();
1826 moveCursorUpdate(false);
1827 owner_->showState();
1831 if (!TEXT(bv_)->mark_set)
1832 beforeChange(TEXT(bv_));
1833 update(TEXT(bv_), BufferView::UPDATE);
1834 TEXT(bv_)->CursorDown(bv_);
1835 TEXT(bv_)->FinishUndo();
1836 moveCursorUpdate(false);
1837 owner_->showState();
1840 case LFUN_UP_PARAGRAPH:
1841 if (!TEXT(bv_)->mark_set)
1842 beforeChange(TEXT(bv_));
1843 update(TEXT(bv_), BufferView::UPDATE);
1844 TEXT(bv_)->CursorUpParagraph(bv_);
1845 TEXT(bv_)->FinishUndo();
1846 moveCursorUpdate(false);
1847 owner_->showState();
1850 case LFUN_DOWN_PARAGRAPH:
1851 if (!TEXT(bv_)->mark_set)
1852 beforeChange(TEXT(bv_));
1853 update(TEXT(bv_), BufferView::UPDATE);
1854 TEXT(bv_)->CursorDownParagraph(bv_);
1855 TEXT(bv_)->FinishUndo();
1856 moveCursorUpdate(false);
1857 owner_->showState();
1861 if (!TEXT(bv_)->mark_set)
1862 beforeChange(TEXT(bv_));
1863 update(TEXT(bv_), BufferView::UPDATE);
1864 cursorPrevious(TEXT(bv_));
1865 TEXT(bv_)->FinishUndo();
1866 moveCursorUpdate(false);
1867 owner_->showState();
1871 if (!TEXT(bv_)->mark_set)
1872 beforeChange(TEXT(bv_));
1873 update(TEXT(bv_), BufferView::UPDATE);
1874 cursorNext(TEXT(bv_));
1875 TEXT(bv_)->FinishUndo();
1876 moveCursorUpdate(false);
1877 owner_->showState();
1881 if (!TEXT(bv_)->mark_set)
1882 beforeChange(TEXT(bv_));
1883 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1884 TEXT(bv_)->CursorHome(bv_);
1885 TEXT(bv_)->FinishUndo();
1886 moveCursorUpdate(false);
1887 owner_->showState();
1891 if (!TEXT(bv_)->mark_set)
1892 beforeChange(TEXT(bv_));
1894 BufferView::SELECT|BufferView::FITCUR);
1895 TEXT(bv_)->CursorEnd(bv_);
1896 TEXT(bv_)->FinishUndo();
1897 moveCursorUpdate(false);
1898 owner_->showState();
1901 case LFUN_SHIFT_TAB:
1903 if (!TEXT(bv_)->mark_set)
1904 beforeChange(TEXT(bv_));
1906 BufferView::SELECT|BufferView::FITCUR);
1907 TEXT(bv_)->CursorTab(bv_);
1908 TEXT(bv_)->FinishUndo();
1909 moveCursorUpdate(false);
1910 owner_->showState();
1913 case LFUN_WORDRIGHT:
1914 if (!TEXT(bv_)->mark_set)
1915 beforeChange(TEXT(bv_));
1916 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1917 if (TEXT(bv_)->cursor.par()->isRightToLeftPar(buffer_->params))
1918 TEXT(bv_)->CursorLeftOneWord(bv_);
1920 TEXT(bv_)->CursorRightOneWord(bv_);
1921 TEXT(bv_)->FinishUndo();
1922 moveCursorUpdate(false);
1923 owner_->showState();
1927 if (!TEXT(bv_)->mark_set)
1928 beforeChange(TEXT(bv_));
1929 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
1930 if (TEXT(bv_)->cursor.par()->isRightToLeftPar(buffer_->params))
1931 TEXT(bv_)->CursorRightOneWord(bv_);
1933 TEXT(bv_)->CursorLeftOneWord(bv_);
1934 TEXT(bv_)->FinishUndo();
1935 moveCursorUpdate(false);
1936 owner_->showState();
1939 case LFUN_BEGINNINGBUF:
1940 if (!TEXT(bv_)->mark_set)
1941 beforeChange(TEXT(bv_));
1943 BufferView::SELECT|BufferView::FITCUR);
1944 TEXT(bv_)->CursorTop(bv_);
1945 TEXT(bv_)->FinishUndo();
1946 moveCursorUpdate(false);
1947 owner_->showState();
1951 if (!TEXT(bv_)->mark_set)
1952 beforeChange(TEXT(bv_));
1954 BufferView::SELECT|BufferView::FITCUR);
1955 TEXT(bv_)->CursorBottom(bv_);
1956 TEXT(bv_)->FinishUndo();
1957 moveCursorUpdate(false);
1958 owner_->showState();
1962 /* cursor selection ---------------------------- */
1965 BufferView::SELECT|BufferView::FITCUR);
1966 if (TEXT(bv_)->cursor.par()->isRightToLeftPar(buffer_->params))
1967 TEXT(bv_)->CursorLeft(bv_);
1969 TEXT(bv_)->CursorRight(bv_);
1970 TEXT(bv_)->FinishUndo();
1971 moveCursorUpdate(true);
1972 owner_->showState();
1977 BufferView::SELECT|BufferView::FITCUR);
1978 if (TEXT(bv_)->cursor.par()->isRightToLeftPar(buffer_->params))
1979 TEXT(bv_)->CursorRight(bv_);
1981 TEXT(bv_)->CursorLeft(bv_);
1982 TEXT(bv_)->FinishUndo();
1983 moveCursorUpdate(true);
1984 owner_->showState();
1989 BufferView::SELECT|BufferView::FITCUR);
1990 TEXT(bv_)->CursorUp(bv_);
1991 TEXT(bv_)->FinishUndo();
1992 moveCursorUpdate(true);
1993 owner_->showState();
1998 BufferView::SELECT|BufferView::FITCUR);
1999 TEXT(bv_)->CursorDown(bv_);
2000 TEXT(bv_)->FinishUndo();
2001 moveCursorUpdate(true);
2002 owner_->showState();
2005 case LFUN_UP_PARAGRAPHSEL:
2007 BufferView::SELECT|BufferView::FITCUR);
2008 TEXT(bv_)->CursorUpParagraph(bv_);
2009 TEXT(bv_)->FinishUndo();
2010 moveCursorUpdate(true);
2011 owner_->showState();
2014 case LFUN_DOWN_PARAGRAPHSEL:
2016 BufferView::SELECT|BufferView::FITCUR);
2017 TEXT(bv_)->CursorDownParagraph(bv_);
2018 TEXT(bv_)->FinishUndo();
2019 moveCursorUpdate(true);
2020 owner_->showState();
2024 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2025 cursorPrevious(TEXT(bv_));
2026 TEXT(bv_)->FinishUndo();
2027 moveCursorUpdate(true);
2028 owner_->showState();
2032 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2033 cursorNext(TEXT(bv_));
2034 TEXT(bv_)->FinishUndo();
2035 moveCursorUpdate(true);
2036 owner_->showState();
2040 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2041 TEXT(bv_)->CursorHome(bv_);
2042 TEXT(bv_)->FinishUndo();
2043 moveCursorUpdate(true);
2044 owner_->showState();
2048 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2049 TEXT(bv_)->CursorEnd(bv_);
2050 TEXT(bv_)->FinishUndo();
2051 moveCursorUpdate(true);
2052 owner_->showState();
2055 case LFUN_WORDRIGHTSEL:
2056 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2057 if (TEXT(bv_)->cursor.par()->isRightToLeftPar(buffer_->params))
2058 TEXT(bv_)->CursorLeftOneWord(bv_);
2060 TEXT(bv_)->CursorRightOneWord(bv_);
2061 TEXT(bv_)->FinishUndo();
2062 moveCursorUpdate(true);
2063 owner_->showState();
2066 case LFUN_WORDLEFTSEL:
2067 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2068 if (TEXT(bv_)->cursor.par()->isRightToLeftPar(buffer_->params))
2069 TEXT(bv_)->CursorRightOneWord(bv_);
2071 TEXT(bv_)->CursorLeftOneWord(bv_);
2072 TEXT(bv_)->FinishUndo();
2073 moveCursorUpdate(true);
2074 owner_->showState();
2077 case LFUN_BEGINNINGBUFSEL:
2078 if (TEXT(bv_)->inset_owner)
2080 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2081 TEXT(bv_)->CursorTop(bv_);
2082 TEXT(bv_)->FinishUndo();
2083 moveCursorUpdate(true);
2084 owner_->showState();
2087 case LFUN_ENDBUFSEL:
2088 if (TEXT(bv_)->inset_owner)
2091 BufferView::SELECT|BufferView::FITCUR);
2092 TEXT(bv_)->CursorBottom(bv_);
2093 TEXT(bv_)->FinishUndo();
2094 moveCursorUpdate(true);
2095 owner_->showState();
2098 // --- text changing commands ------------------------
2099 case LFUN_BREAKLINE:
2100 beforeChange(TEXT(bv_));
2101 TEXT(bv_)->InsertChar(bv_, LyXParagraph::META_NEWLINE);
2103 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2104 moveCursorUpdate(false);
2107 case LFUN_PROTECTEDSPACE:
2109 LyXLayout const & style = textclasslist
2110 .Style(buffer_->params.textclass,
2111 TEXT(bv_)->cursor.par()->GetLayout());
2113 if (style.free_spacing) {
2114 TEXT(bv_)->InsertChar(bv_, ' ');
2117 | BufferView::FITCUR
2118 | BufferView::CHANGE);
2120 bv_->protectedBlank(TEXT(bv_));
2122 moveCursorUpdate(false);
2127 if (TEXT(bv_)->mark_set) {
2128 beforeChange(TEXT(bv_));
2130 BufferView::SELECT|BufferView::FITCUR);
2131 owner_->getLyXFunc()->setMessage(N_("Mark removed"));
2133 beforeChange(TEXT(bv_));
2134 TEXT(bv_)->mark_set = 1;
2136 BufferView::SELECT|BufferView::FITCUR);
2137 owner_->getLyXFunc()->setMessage(N_("Mark set"));
2139 TEXT(bv_)->sel_cursor = TEXT(bv_)->cursor;
2143 if (!TEXT(bv_)->selection) {
2144 TEXT(bv_)->Delete(bv_);
2145 TEXT(bv_)->sel_cursor =
2149 | BufferView::FITCUR
2150 | BufferView::CHANGE);
2151 // It is possible to make it a lot faster still
2152 // just comment out the line below...
2157 moveCursorUpdate(false);
2158 owner_->showState();
2162 case LFUN_DELETE_SKIP:
2164 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
2166 LyXCursor cursor = TEXT(bv_)->cursor;
2168 if (!TEXT(bv_)->selection) {
2169 if (cursor.pos() == cursor.par()->size()) {
2170 TEXT(bv_)->CursorRight(bv_);
2171 cursor = TEXT(bv_)->cursor;
2172 if (cursor.pos() == 0
2173 && !(cursor.par()->params.spaceTop()
2174 == VSpace (VSpace::NONE))) {
2175 TEXT(bv_)->SetParagraph
2177 cursor.par()->params.lineTop(),
2178 cursor.par()->params.lineBottom(),
2179 cursor.par()->params.pagebreakTop(),
2180 cursor.par()->params.pagebreakBottom(),
2181 VSpace(VSpace::NONE),
2182 cursor.par()->params.spaceBottom(),
2183 cursor.par()->params.align(),
2184 cursor.par()->params.labelWidthString(), 0);
2185 TEXT(bv_)->CursorLeft(bv_);
2187 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2189 TEXT(bv_)->CursorLeft(bv_);
2190 TEXT(bv_)->Delete(bv_);
2191 TEXT(bv_)->sel_cursor =
2194 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2197 TEXT(bv_)->Delete(bv_);
2198 TEXT(bv_)->sel_cursor =
2201 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2209 /* -------> Delete word forward. */
2210 case LFUN_DELETE_WORD_FORWARD:
2211 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2212 TEXT(bv_)->DeleteWordForward(bv_);
2213 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2214 moveCursorUpdate(false);
2215 owner_->showState();
2218 /* -------> Delete word backward. */
2219 case LFUN_DELETE_WORD_BACKWARD:
2220 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2221 TEXT(bv_)->DeleteWordBackward(bv_);
2222 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2223 moveCursorUpdate(false);
2224 owner_->showState();
2227 /* -------> Kill to end of line. */
2228 case LFUN_DELETE_LINE_FORWARD:
2229 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2230 TEXT(bv_)->DeleteLineForward(bv_);
2231 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2232 moveCursorUpdate(false);
2235 /* -------> Set mark off. */
2237 beforeChange(TEXT(bv_));
2238 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2239 TEXT(bv_)->sel_cursor = TEXT(bv_)->cursor;
2240 owner_->getLyXFunc()->setMessage(N_("Mark off"));
2243 /* -------> Set mark on. */
2245 beforeChange(TEXT(bv_));
2246 TEXT(bv_)->mark_set = 1;
2247 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR);
2248 TEXT(bv_)->sel_cursor = TEXT(bv_)->cursor;
2249 owner_->getLyXFunc()->setMessage(N_("Mark on"));
2252 case LFUN_BACKSPACE:
2254 if (!TEXT(bv_)->selection) {
2255 if (owner_->getIntl()->getTrans().backspace()) {
2256 TEXT(bv_)->Backspace(bv_);
2257 TEXT(bv_)->sel_cursor =
2260 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2261 // It is possible to make it a lot faster still
2262 // just comment out the line below...
2268 owner_->showState();
2273 case LFUN_BACKSPACE_SKIP:
2275 // Reverse the effect of LFUN_BREAKPARAGRAPH_SKIP.
2277 LyXCursor cursor = TEXT(bv_)->cursor;
2279 if (!TEXT(bv_)->selection) {
2280 if (cursor.pos() == 0
2281 && !(cursor.par()->params.spaceTop()
2282 == VSpace (VSpace::NONE))) {
2283 TEXT(bv_)->SetParagraph
2285 cursor.par()->params.lineTop(),
2286 cursor.par()->params.lineBottom(),
2287 cursor.par()->params.pagebreakTop(),
2288 cursor.par()->params.pagebreakBottom(),
2289 VSpace(VSpace::NONE), cursor.par()->params.spaceBottom(),
2290 cursor.par()->params.align(),
2291 cursor.par()->params.labelWidthString(), 0);
2293 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2295 TEXT(bv_)->Backspace(bv_);
2296 TEXT(bv_)->sel_cursor
2299 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2306 case LFUN_BREAKPARAGRAPH:
2308 beforeChange(TEXT(bv_));
2309 TEXT(bv_)->BreakParagraph(bv_, 0);
2311 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2312 TEXT(bv_)->sel_cursor = TEXT(bv_)->cursor;
2314 owner_->showState();
2318 case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
2320 beforeChange(TEXT(bv_));
2321 TEXT(bv_)->BreakParagraph(bv_, 1);
2323 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2324 TEXT(bv_)->sel_cursor = TEXT(bv_)->cursor;
2326 owner_->showState();
2330 case LFUN_BREAKPARAGRAPH_SKIP:
2332 // When at the beginning of a paragraph, remove
2333 // indentation and add a "defskip" at the top.
2334 // Otherwise, do the same as LFUN_BREAKPARAGRAPH.
2336 LyXCursor cursor = TEXT(bv_)->cursor;
2338 beforeChange(TEXT(bv_));
2339 if (cursor.pos() == 0) {
2340 if (cursor.par()->params.spaceTop() == VSpace(VSpace::NONE)) {
2341 TEXT(bv_)->SetParagraph
2343 cursor.par()->params.lineTop(),
2344 cursor.par()->params.lineBottom(),
2345 cursor.par()->params.pagebreakTop(),
2346 cursor.par()->params.pagebreakBottom(),
2347 VSpace(VSpace::DEFSKIP), cursor.par()->params.spaceBottom(),
2348 cursor.par()->params.align(),
2349 cursor.par()->params.labelWidthString(), 1);
2350 //update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2354 TEXT(bv_)->BreakParagraph(bv_, 0);
2355 //update(BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2359 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2360 TEXT(bv_)->sel_cursor = cursor;
2362 owner_->showState();
2366 case LFUN_PARAGRAPH_SPACING:
2368 LyXParagraph * par = TEXT(bv_)->cursor.par();
2369 Spacing::Space cur_spacing = par->params.spacing().getSpace();
2370 float cur_value = 1.0;
2371 if (cur_spacing == Spacing::Other) {
2372 cur_value = par->params.spacing().getValue();
2375 istringstream istr(argument.c_str());
2379 Spacing::Space new_spacing = cur_spacing;
2380 float new_value = cur_value;
2382 lyxerr << "Missing argument to `paragraph-spacing'"
2384 } else if (tmp == "single") {
2385 new_spacing = Spacing::Single;
2386 } else if (tmp == "onehalf") {
2387 new_spacing = Spacing::Onehalf;
2388 } else if (tmp == "double") {
2389 new_spacing = Spacing::Double;
2390 } else if (tmp == "other") {
2391 new_spacing = Spacing::Other;
2394 lyxerr << "new_value = " << tmpval << endl;
2397 } else if (tmp == "default") {
2398 new_spacing = Spacing::Default;
2400 lyxerr << _("Unknown spacing argument: ")
2401 << argument << endl;
2403 if (cur_spacing != new_spacing || cur_value != new_value) {
2404 par->params.spacing(Spacing(new_spacing, new_value));
2405 TEXT(bv_)->RedoParagraph(bv_);
2407 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2413 beforeChange(TEXT(bv_));
2414 TEXT(bv_)->InsertChar(bv_, '\"'); // This " matches the single quote in the code
2415 update(TEXT(bv_), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2416 moveCursorUpdate(false);
2422 InsetCommandParams p;
2423 if (action == LFUN_HTMLURL)
2424 p.setCmdName("htmlurl");
2426 p.setCmdName("url");
2427 owner_->getDialogs()->createUrl( p.getAsString() );
2431 case LFUN_INSERT_URL:
2433 InsetCommandParams p;
2434 p.setFromString( argument );
2436 InsetUrl * inset = new InsetUrl( p );
2437 if (!bv_->insertInset(inset))
2440 bv_->updateInset( inset, true );
2444 case LFUN_INSET_TEXT:
2446 InsetText * new_inset = new InsetText;
2447 if (bv_->insertInset(new_inset))
2448 new_inset->Edit(bv_, 0, 0, 0);
2454 case LFUN_INSET_ERT:
2456 InsetERT * new_inset = new InsetERT;
2457 if (bv_->insertInset(new_inset))
2458 new_inset->Edit(bv_, 0, 0, 0);
2464 case LFUN_INSET_EXTERNAL:
2466 InsetExternal * new_inset = new InsetExternal;
2467 if (bv_->insertInset(new_inset))
2468 new_inset->Edit(bv_, 0, 0, 0);
2474 case LFUN_INSET_FOOTNOTE:
2476 InsetFoot * new_inset = new InsetFoot;
2477 if (bv_->insertInset(new_inset))
2478 new_inset->Edit(bv_, 0, 0, 0);
2484 case LFUN_INSET_MARGINAL:
2486 InsetMarginal * new_inset = new InsetMarginal;
2487 if (bv_->insertInset(new_inset))
2488 new_inset->Edit(bv_, 0, 0, 0);
2494 case LFUN_INSET_MINIPAGE:
2496 InsetMinipage * new_inset = new InsetMinipage;
2497 if (bv_->insertInset(new_inset))
2498 new_inset->Edit(bv_, 0, 0, 0);
2504 case LFUN_INSET_FLOAT:
2506 // check if the float type exist
2507 if (floatList.typeExist(argument)) {
2508 InsetFloat * new_inset = new InsetFloat(argument);
2509 if (bv_->insertInset(new_inset))
2510 new_inset->Edit(bv_, 0, 0, 0);
2514 lyxerr << "Non-existant float type: "
2515 << argument << endl;
2521 case LFUN_INSET_LIST:
2523 InsetList * new_inset = new InsetList;
2524 if (bv_->insertInset(new_inset))
2525 new_inset->Edit(bv_, 0, 0, 0);
2531 case LFUN_INSET_THEOREM:
2533 InsetTheorem * new_inset = new InsetTheorem;
2534 if (bv_->insertInset(new_inset))
2535 new_inset->Edit(bv_, 0, 0, 0);
2541 case LFUN_INSET_CAPTION:
2543 // Do we have a locking inset...
2544 if (bv_->theLockingInset()) {
2545 lyxerr << "Locking inset code: "
2546 << static_cast<int>(bv_->theLockingInset()->LyxCode());
2547 InsetCaption * new_inset = new InsetCaption;
2548 new_inset->setOwner(bv_->theLockingInset());
2549 new_inset->SetAutoBreakRows(true);
2550 new_inset->SetDrawFrame(0, InsetText::LOCKED);
2551 new_inset->SetFrameColor(0, LColor::footnoteframe);
2552 if (bv_->insertInset(new_inset))
2553 new_inset->Edit(bv_, 0, 0, 0);
2560 case LFUN_INSET_TABULAR:
2563 if (!argument.empty())
2564 ::sscanf(argument.c_str(),"%d%d", &r, &c);
2565 InsetTabular * new_inset =
2566 new InsetTabular(*buffer_, r, c);
2568 TEXT(bv_)->real_current_font.isRightToLeft();
2569 if (!open_new_inset(new_inset, rtl))
2574 // --- lyxserver commands ----------------------------
2576 case LFUN_CHARATCURSOR:
2578 LyXParagraph::size_type pos = TEXT(bv_)->cursor.pos();
2579 if (pos < TEXT(bv_)->cursor.par()->size())
2580 owner_->getLyXFunc()->setMessage(
2581 tostr(TEXT(bv_)->cursor.par()->GetChar(pos)));
2583 owner_->getLyXFunc()->setMessage("EOF");
2588 owner_->getLyXFunc()->setMessage(tostr(TEXT(bv_)->cursor.x())
2590 + tostr(TEXT(bv_)->cursor.y()));
2597 ::sscanf(argument.c_str(), " %d %d", &x, &y);
2598 TEXT(bv_)->SetCursorFromCoordinates(bv_, x, y);
2602 case LFUN_GETLAYOUT:
2603 owner_->getLyXFunc()->setMessage(tostr(TEXT(bv_)->cursor.par()->layout));
2608 LyXFont & font = TEXT(bv_)->current_font;
2609 if (font.shape() == LyXFont::ITALIC_SHAPE)
2610 owner_->getLyXFunc()->setMessage("E");
2611 else if (font.shape() == LyXFont::SMALLCAPS_SHAPE)
2612 owner_->getLyXFunc()->setMessage("N");
2614 owner_->getLyXFunc()->setMessage("0");
2621 LyXFont & font = TEXT(bv_)->current_font;
2622 if (font.latex() == LyXFont::ON)
2623 owner_->getLyXFunc()->setMessage("L");
2625 owner_->getLyXFunc()->setMessage("0");
2629 // --- accented characters ---------------------------
2632 case LFUN_CIRCUMFLEX:
2642 case LFUN_SPECIAL_CARON:
2645 case LFUN_HUNG_UMLAUT:
2648 if (argument.empty()) {
2650 owner_->getLyXFunc()->handleKeyFunc(action);
2652 owner_->getLyXFunc()->handleKeyFunc(action);
2653 owner_->getIntl()->getTrans()
2654 .TranslateAndInsert(argument[0], TEXT(bv_));
2657 | BufferView::FITCUR
2658 | BufferView::CHANGE);
2662 // --- insert characters ----------------------------------------
2664 case LFUN_MATH_DELIM:
2665 case LFUN_INSERT_MATRIX:
2668 if (open_new_inset(new InsetFormula(false))) {
2669 bv_->theLockingInset()
2670 ->LocalDispatch(bv_, action, argument);
2676 case LFUN_INSERT_MATH:
2681 InsetFormula * f = new InsetFormula(true);
2683 f->LocalDispatch(bv_, LFUN_INSERT_MATH, argument);
2687 case LFUN_MATH_DISPLAY:
2690 open_new_inset(new InsetFormula(true));
2694 case LFUN_MATH_MACRO:
2699 owner_->getLyXFunc()->setErrorMessage(N_("Missing argument"));
2701 string const s1 = token(s, ' ', 1);
2702 int const na = s1.empty() ? 0 : lyx::atoi(s1);
2703 open_new_inset(new InsetFormulaMacro(token(s, ' ', 0), na));
2709 case LFUN_MATH_MODE: // Open or create a math inset
2712 open_new_inset(new InsetFormula);
2713 owner_->getLyXFunc()->setMessage(N_("Math editor mode"));
2717 case LFUN_CITATION_INSERT:
2719 InsetCommandParams p;
2720 p.setFromString( argument );
2722 InsetCitation * inset = new InsetCitation( p );
2723 if (!bv_->insertInset(inset))
2726 bv_->updateInset( inset, true );
2730 case LFUN_INSERT_BIBTEX:
2732 // ale970405+lasgoutt970425
2733 // The argument can be up to two tokens separated
2734 // by a space. The first one is the bibstyle.
2735 string const db = token(argument, ' ', 0);
2736 string bibstyle = token(argument, ' ', 1);
2737 if (bibstyle.empty())
2740 InsetCommandParams p( "BibTeX", db, bibstyle );
2741 InsetBibtex * inset = new InsetBibtex(p);
2743 if (bv_->insertInset(inset)) {
2744 if (argument.empty())
2745 inset->Edit(bv_, 0, 0, 0);
2751 // BibTeX data bases
2752 case LFUN_BIBDB_ADD:
2754 InsetBibtex * inset =
2755 static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
2757 inset->addDatabase(argument);
2762 case LFUN_BIBDB_DEL:
2764 InsetBibtex * inset =
2765 static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
2767 inset->delDatabase(argument);
2772 case LFUN_BIBTEX_STYLE:
2774 InsetBibtex * inset =
2775 static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
2777 inset->setOptions(argument);
2782 case LFUN_INDEX_CREATE:
2784 InsetCommandParams p( "index" );
2786 if (argument.empty()) {
2787 // Get the word immediately preceding the cursor
2788 LyXParagraph::size_type curpos =
2789 TEXT(bv_)->cursor.pos() - 1;
2793 curstring = TEXT(bv_)
2794 ->cursor.par()->GetWord(curpos);
2796 p.setContents( curstring );
2798 p.setContents( argument );
2801 owner_->getDialogs()->createIndex( p.getAsString() );
2805 case LFUN_INDEX_INSERT:
2807 InsetCommandParams p;
2808 p.setFromString(argument);
2809 InsetIndex * inset = new InsetIndex(p);
2811 if (!bv_->insertInset(inset))
2814 bv_->updateInset(inset, true);
2818 case LFUN_INDEX_INSERT_LAST:
2820 // Get word immediately preceding the cursor
2821 LyXParagraph::size_type curpos =
2822 TEXT(bv_)->cursor.pos() - 1;
2823 // Can't do that at the beginning of a paragraph
2824 if (curpos < 0) break;
2826 string const curstring(TEXT(bv_)
2827 ->cursor.par()->GetWord(curpos));
2829 InsetCommandParams p("index", curstring);
2830 InsetIndex * inset = new InsetIndex(p);
2832 if (!bv_->insertInset(inset))
2835 bv_->updateInset(inset, true);
2839 case LFUN_INDEX_PRINT:
2841 InsetCommandParams p("printindex");
2842 Inset * inset = new InsetPrintIndex(p);
2843 if (!bv_->insertInset(inset, "Standard", true))
2848 case LFUN_PARENTINSERT:
2850 lyxerr << "arg " << argument << endl;
2851 InsetCommandParams p( "lyxparent", argument );
2852 Inset * inset = new InsetParent(p, *buffer_);
2853 if (!bv_->insertInset(inset, "Standard", true))
2859 case LFUN_CHILD_INSERT:
2861 InsetInclude::Params p;
2862 p.cparams.setFromString(argument);
2863 p.masterFilename_ = buffer_->fileName();
2865 InsetInclude * inset = new InsetInclude(p);
2866 if (!bv_->insertInset(inset))
2869 bv_->updateInset(inset, true);
2870 bv_->owner()->getDialogs()->showInclude(inset);
2875 case LFUN_FLOAT_LIST:
2877 // We should check the argument for validity. (Lgb)
2878 Inset * inset = new InsetFloatList(argument);
2879 if (!bv_->insertInset(inset, "Standard", true))
2884 case LFUN_INSERT_NOTE:
2888 case LFUN_SELFINSERT:
2890 LyXFont const old_font(TEXT(bv_)->real_current_font);
2891 for (string::size_type i = 0; i < argument.length(); ++i) {
2892 TEXT(bv_)->InsertChar(bv_, argument[i]);
2893 // This needs to be in the loop, or else we
2894 // won't break lines correctly. (Asger)
2896 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2898 TEXT(bv_)->sel_cursor = TEXT(bv_)->cursor;
2899 moveCursorUpdate(false);
2901 // real_current_font.number can change so we need to
2902 // update the minibuffer
2903 if (old_font != TEXT(bv_)->real_current_font)
2904 owner_->showState();
2908 case LFUN_DATE_INSERT: // jdblair: date-insert cmd
2912 time_t now_time_t = time(NULL);
2913 now_tm = localtime(&now_time_t);
2914 setlocale(LC_TIME, "");
2916 if (!argument.empty())
2919 arg = lyxrc.date_insert_format;
2921 int const datetmp_len =
2922 ::strftime(datetmp, 32, arg.c_str(), now_tm);
2923 for (int i = 0; i < datetmp_len; i++) {
2924 TEXT(bv_)->InsertChar(bv_, datetmp[i]);
2926 BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
2929 TEXT(bv_)->sel_cursor = TEXT(bv_)->cursor;
2930 moveCursorUpdate(false);
2934 case LFUN_UNKNOWN_ACTION:
2935 owner_->getLyXFunc()->setErrorMessage(N_("Unknow function!"));
2946 void BufferView::Pimpl::insertNote()
2948 InsetInfo * new_inset = new InsetInfo();
2949 bv_->insertInset(new_inset);
2950 new_inset->Edit(bv_, 0, 0, 0);
2954 // Open and lock an updatable inset
2955 bool BufferView::Pimpl::open_new_inset(UpdatableInset * new_inset, bool behind)
2957 beforeChange(TEXT(bv_));
2958 TEXT(bv_)->FinishUndo();
2959 if (!bv_->insertInset(new_inset)) {
2964 LyXFont & font = bv_->getLyXText()->real_current_font;
2965 new_inset->Edit(bv_, new_inset->width(bv_, font), 0, 0);
2967 new_inset->Edit(bv_, 0, 0, 0);