2 * \file BufferView_pimpl.C
3 * Copyright 2002 the LyX Team
4 * Read the file COPYING
12 #pragma implementation
15 #include "BufferView_pimpl.h"
16 #include "frontends/WorkArea.h"
17 #include "frontends/screen.h"
18 #include "frontends/LyXScreenFactory.h"
19 #include "frontends/WorkAreaFactory.h"
20 #include "frontends/Dialogs.h"
21 #include "frontends/Alert.h"
22 #include "frontends/FileDialog.h"
25 #include "paragraph.h"
26 #include "frontends/LyXView.h"
27 #include "commandtags.h"
30 #include "bufferview_funcs.h"
31 #include "TextCache.h"
32 #include "bufferlist.h"
35 // added for Dispatch functions
38 #include "FloatList.h"
40 #include "ParagraphParameters.h"
41 #include "undo_funcs.h"
42 #include "funcrequest.h"
44 #include "insets/insetbib.h"
45 #include "insets/insettext.h"
46 #include "insets/inseturl.h"
47 #include "insets/insetlatexaccent.h"
48 #include "insets/insettoc.h"
49 #include "insets/insetref.h"
50 #include "insets/insetparent.h"
51 #include "insets/insetindex.h"
52 #include "insets/insetinclude.h"
53 #include "insets/insetcite.h"
54 #include "insets/insetgraphics.h"
55 #include "insets/insetmarginal.h"
56 #include "insets/insettabular.h"
57 #include "insets/insetcaption.h"
58 #include "insets/insetfloatlist.h"
60 #include "mathed/formulabase.h"
62 #include "graphics/Previews.h"
64 #include "support/LAssert.h"
65 #include "support/lstrings.h"
66 #include "support/filetools.h"
68 #include <boost/bind.hpp>
69 #include <boost/signals/connection.hpp>
86 /* the selection possible is needed, that only motion events are
87 * used, where the bottom press event was on the drawing area too */
88 bool selection_possible = false;
90 extern BufferList bufferlist;
91 extern int bibitemMaxWidth(BufferView *, LyXFont const &);
96 unsigned int const saved_positions_num = 20;
98 // All the below connection objects are needed because of a bug in some
99 // versions of GCC (<=2.96 are on the suspects list.) By having and assigning
100 // to these connections we avoid a segfault upon startup, and also at exit.
103 boost::signals::connection timecon;
104 boost::signals::connection doccon;
105 boost::signals::connection resizecon;
106 boost::signals::connection bpresscon;
107 boost::signals::connection breleasecon;
108 boost::signals::connection motioncon;
109 boost::signals::connection doublecon;
110 boost::signals::connection triplecon;
111 boost::signals::connection kpresscon;
112 boost::signals::connection selectioncon;
113 boost::signals::connection lostcon;
118 BufferView::Pimpl::Pimpl(BufferView * bv, LyXView * owner,
119 int xpos, int ypos, int width, int height)
120 : bv_(bv), owner_(owner), buffer_(0), cursor_timeout(400),
121 using_xterm_cursor(false)
123 workarea_.reset(WorkAreaFactory::create(xpos, ypos, width, height));
124 screen_.reset(LyXScreenFactory::create(workarea()));
127 doccon = workarea().scrollDocView
128 .connect(boost::bind(&BufferView::Pimpl::scrollDocView, this, _1));
129 resizecon = workarea().workAreaResize
130 .connect(boost::bind(&BufferView::Pimpl::workAreaResize, this));
131 bpresscon = workarea().workAreaButtonPress
132 .connect(boost::bind(&BufferView::Pimpl::workAreaButtonPress, this, _1, _2, _3));
133 breleasecon = workarea().workAreaButtonRelease
134 .connect(boost::bind(&BufferView::Pimpl::workAreaButtonRelease, this, _1, _2, _3));
135 motioncon = workarea().workAreaMotionNotify
136 .connect(boost::bind(&BufferView::Pimpl::workAreaMotionNotify, this, _1, _2, _3));
137 doublecon = workarea().workAreaDoubleClick
138 .connect(boost::bind(&BufferView::Pimpl::doubleClick, this, _1, _2, _3));
139 triplecon = workarea().workAreaTripleClick
140 .connect(boost::bind(&BufferView::Pimpl::tripleClick, this, _1, _2, _3));
141 kpresscon = workarea().workAreaKeyPress
142 .connect(boost::bind(&BufferView::Pimpl::workAreaKeyPress, this, _1, _2));
143 selectioncon = workarea().selectionRequested
144 .connect(boost::bind(&BufferView::Pimpl::selectionRequested, this));
145 lostcon = workarea().selectionLost
146 .connect(boost::bind(&BufferView::Pimpl::selectionLost, this));
148 timecon = cursor_timeout.timeout
149 .connect(boost::bind(&BufferView::Pimpl::cursorToggle, this));
150 cursor_timeout.start();
151 saved_positions.resize(saved_positions_num);
155 WorkArea & BufferView::Pimpl::workarea() const
157 return *workarea_.get();
161 LyXScreen & BufferView::Pimpl::screen() const
163 return *screen_.get();
167 Painter & BufferView::Pimpl::painter() const
169 return workarea().getPainter();
173 void BufferView::Pimpl::buffer(Buffer * b)
175 lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
178 buffer_->delUser(bv_);
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");
191 // set current buffer
194 if (bufferlist.getState() == BufferList::CLOSING) return;
196 // if we are closing the buffer, use the first buffer as current
198 buffer_ = bufferlist.first();
202 lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl;
203 buffer_->addUser(bv_);
205 // If we don't have a text object for this, we make one
206 if (bv_->text == 0) {
207 resizeCurrentBuffer();
210 // FIXME: needed when ?
212 screen().topCursorVisible(bv_->text->cursor, bv_->text->first_y);
214 // Similarly, buffer-dependent dialogs should be updated or
215 // hidden. This should go here because some dialogs (eg ToC)
216 // require bv_->text.
217 owner_->getDialogs().updateBufferDependent(true);
219 lyxerr[Debug::INFO] << " No Buffer!" << endl;
220 owner_->getDialogs().hideBufferDependent();
222 // Also remove all remaining text's from the testcache.
223 // (there should not be any!) (if there is any it is a
225 if (lyxerr.debugging())
226 textcache.show(lyxerr, "buffer delete all");
232 owner_->updateMenubar();
233 owner_->updateToolbar();
234 owner_->updateLayoutChoice();
235 owner_->updateWindowTitle();
237 if (grfx::Previews::activated() && buffer_)
238 grfx::Previews::get().generateBufferPreviews(*buffer_);
242 bool BufferView::Pimpl::fitCursor()
246 if (bv_->theLockingInset()) {
247 bv_->theLockingInset()->fitInsetCursor(bv_);
250 ret = screen().fitCursor(bv_->text, bv_);
253 bv_->owner()->getDialogs().updateParagraph();
260 void BufferView::Pimpl::redoCurrentBuffer()
262 lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
263 if (buffer_ && bv_->text) {
264 resizeCurrentBuffer();
266 owner_->updateLayoutChoice();
272 int BufferView::Pimpl::resizeCurrentBuffer()
274 lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
277 Paragraph * selstartpar = 0;
278 Paragraph * selendpar = 0;
279 UpdatableInset * the_locking_inset = 0;
282 pos_type selstartpos = 0;
283 pos_type selendpos = 0;
284 bool selection = false;
285 bool mark_set = false;
287 owner_->prohibitInput();
289 owner_->message(_("Formatting document..."));
292 par = bv_->text->cursor.par();
293 pos = bv_->text->cursor.pos();
294 selstartpar = bv_->text->selection.start.par();
295 selstartpos = bv_->text->selection.start.pos();
296 selendpar = bv_->text->selection.end.par();
297 selendpos = bv_->text->selection.end.pos();
298 selection = bv_->text->selection.set();
299 mark_set = bv_->text->selection.mark();
300 the_locking_inset = bv_->theLockingInset();
301 buffer_->resizeInsets(bv_);
302 // I don't think the delete and new are necessary here we just could
303 // call only init! (Jug 20020419)
305 bv_->text = new LyXText(bv_);
306 bv_->text->init(bv_);
308 // See if we have a text in TextCache that fits
309 // the new buffer_ with the correct width.
310 bv_->text = textcache.findFit(buffer_, workarea().workWidth());
312 if (lyxerr.debugging()) {
313 lyxerr << "Found a LyXText that fits:\n";
314 textcache.show(lyxerr, make_pair(buffer_, make_pair(workarea().workWidth(), bv_->text)));
316 // Set the owner of the newly found text
317 // bv_->text->owner(bv_);
318 if (lyxerr.debugging())
319 textcache.show(lyxerr, "resizeCurrentBuffer");
321 bv_->text = new LyXText(bv_);
322 bv_->text->init(bv_);
323 //buffer_->resizeInsets(bv_);
328 bv_->text->selection.set(true);
329 // At this point just to avoid the Delete-Empty-Paragraph-
330 // Mechanism when setting the cursor.
331 bv_->text->selection.mark(mark_set);
333 bv_->text->setCursor(bv_, selstartpar, selstartpos);
334 bv_->text->selection.cursor = bv_->text->cursor;
335 bv_->text->setCursor(bv_, selendpar, selendpos);
336 bv_->text->setSelection(bv_);
337 bv_->text->setCursor(bv_, par, pos);
339 bv_->text->setCursor(bv_, par, pos);
340 bv_->text->selection.cursor = bv_->text->cursor;
341 bv_->text->selection.set(false);
343 // remake the inset locking
344 bv_->theLockingInset(the_locking_inset);
347 bv_->text->first_y = screen().topCursorVisible(bv_->text->cursor, bv_->text->first_y);
350 owner_->allowInput();
358 void BufferView::Pimpl::repaint()
360 // Regenerate the screen.
361 screen().redraw(bv_->text, bv_);
365 void BufferView::Pimpl::updateScrollbar()
368 lyxerr[Debug::GUI] << "no text in updateScrollbar" << endl;
369 workarea().setScrollbarParams(0, 0, 0);
373 LyXText const & t = *bv_->text;
375 lyxerr[Debug::GUI] << "Updating scrollbar: h " << t.height << ", first_y "
376 << t.first_y << ", default height " << t.defaultHeight() << endl;
378 workarea().setScrollbarParams(t.height, t.first_y, t.defaultHeight());
382 void BufferView::Pimpl::scrollDocView(int value)
384 lyxerr[Debug::GUI] << "scrollDocView of " << value << endl;
386 if (!buffer_) return;
388 screen().draw(bv_->text, bv_, value);
390 if (!lyxrc.cursor_follows_scrollbar) {
394 LyXText * vbt = bv_->text;
396 int const height = vbt->defaultHeight();
397 int const first = static_cast<int>((bv_->text->first_y + height));
398 int const last = static_cast<int>((bv_->text->first_y + workarea().workHeight() - height));
400 if (vbt->cursor.y() < first)
401 vbt->setCursorFromCoordinates(bv_, 0, first);
402 else if (vbt->cursor.y() > last)
403 vbt->setCursorFromCoordinates(bv_, 0, last);
407 int BufferView::Pimpl::scroll(long time)
412 LyXText const * t = bv_->text;
414 double const diff = t->defaultHeight()
415 + double(time) * double(time) * 0.125;
417 scrollDocView(int(diff));
418 workarea().setScrollbarParams(t->height, t->first_y, t->defaultHeight());
423 void BufferView::Pimpl::workAreaKeyPress(LyXKeySymPtr key,
424 key_modifier::state state)
426 bv_->owner()->getLyXFunc().processKeySym(key, state);
430 void BufferView::Pimpl::workAreaMotionNotify(int x, int y, mouse_button::state state)
432 // Only use motion with button 1
433 if (!(state & mouse_button::button1))
439 // Check for inset locking
440 if (bv_->theLockingInset()) {
441 LyXCursor cursor = bv_->text->cursor;
442 LyXFont font = bv_->text->getFont(buffer_,
443 cursor.par(), cursor.pos());
444 int width = bv_->theLockingInset()->width(bv_, font);
445 int inset_x = font.isVisibleRightToLeft()
446 ? cursor.ix() - width : cursor.ix();
447 int start_x = inset_x + bv_->theLockingInset()->scroll();
449 FuncRequest cmd(bv_, LFUN_MOUSE_MOTION,
450 x - start_x, y - cursor.iy() + bv_->text->first_y, state);
451 bv_->theLockingInset()->localDispatch(cmd);
455 // The test for not selection possible is needed, that only motion
456 // events are used, where the bottom press event was on
457 // the drawing area too
458 if (!selection_possible)
461 screen().hideCursor();
463 Row * cursorrow = bv_->text->cursor.row();
464 bv_->text->setCursorFromCoordinates(bv_, x, y + bv_->text->first_y);
466 // sorry for this but I have a strange error that the y value jumps at
467 // a certain point. This seems like an error in my xforms library or
468 // in some other local environment, but I would like to leave this here
469 // for the moment until I can remove this (Jug 20020418)
470 if (y_before < bv_->text->cursor.y())
471 lyxerr << y_before << ":" << bv_->text->cursor.y() << endl;
473 // This is to allow jumping over large insets
474 if (cursorrow == bv_->text->cursor.row()) {
475 if (y >= int(workarea().workHeight())) {
476 bv_->text->cursorDown(bv_, false);
478 bv_->text->cursorUp(bv_, false);
482 if (!bv_->text->selection.set())
483 update(bv_->text, BufferView::UPDATE); // Maybe an empty line was deleted
485 bv_->text->setSelection(bv_);
486 screen().toggleToggle(bv_->text, bv_);
492 // Single-click on work area
493 void BufferView::Pimpl::workAreaButtonPress(int xpos, int ypos,
494 mouse_button::state button)
499 // ok ok, this is a hack (for xforms)
500 if (button == mouse_button::button4) {
501 scroll(-lyxrc.wheel_jump);
502 // We shouldn't go further down as we really should only do the
503 // scrolling and be done with this. Otherwise we may open some
504 // dialogs (Jug 20020424).
506 } else if (button == mouse_button::button5) {
507 scroll(lyxrc.wheel_jump);
508 // We shouldn't go further down as we really should only do the
509 // scrolling and be done with this. Otherwise we may open some
510 // dialogs (Jug 20020424).
514 Inset * inset_hit = checkInsetHit(bv_->text, xpos, ypos);
516 // Middle button press pastes if we have a selection
517 // We do this here as if the selection was inside an inset
518 // it could get cleared on the unlocking of the inset so
519 // we have to check this first
520 bool paste_internally = false;
521 if (button == mouse_button::button2 && bv_->getLyXText()->selection.set()) {
522 owner_->dispatch(FuncRequest(LFUN_COPY));
523 paste_internally = true;
526 int const screen_first = bv_->text->first_y;
528 if (bv_->theLockingInset()) {
529 // We are in inset locking mode
531 // Check whether the inset was hit. If not reset mode,
532 // otherwise give the event to the inset
533 if (inset_hit == bv_->theLockingInset()) {
534 FuncRequest cmd(bv_, LFUN_MOUSE_PRESS, xpos, ypos, button);
535 bv_->theLockingInset()->localDispatch(cmd);
538 bv_->unlockInset(bv_->theLockingInset());
542 selection_possible = true;
543 screen().hideCursor();
545 // Clear the selection
546 screen().toggleSelection(bv_->text, bv_);
547 bv_->text->clearSelection();
548 bv_->text->fullRebreak(bv_);
552 // Single left click in math inset?
553 if (isHighlyEditableInset(inset_hit)) {
554 // Highly editable inset, like math
555 UpdatableInset * inset = static_cast<UpdatableInset *>(inset_hit);
556 selection_possible = false;
557 owner_->updateLayoutChoice();
558 owner_->message(inset->editMessage());
559 //inset->edit(bv_, xpos, ypos, button);
560 // We just have to lock the inset before calling a PressEvent on it!
561 // we don't need the edit() call here! (Jug20020329)
562 if (!bv_->lockInset(inset)) {
563 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
565 FuncRequest cmd(bv_, LFUN_MOUSE_PRESS, xpos, ypos, button);
566 inset->localDispatch(cmd);
569 // I'm not sure we should continue here if we hit an inset (Jug20020403)
571 // Right click on a footnote flag opens float menu
572 if (button == mouse_button::button3) {
573 selection_possible = false;
577 if (!inset_hit) // otherwise it was already set in checkInsetHit(...)
578 bv_->text->setCursorFromCoordinates(bv_, xpos, ypos + screen_first);
580 bv_->text->selection.cursor = bv_->text->cursor;
581 bv_->text->cursor.x_fix(bv_->text->cursor.x());
583 owner_->updateLayoutChoice();
585 selection_possible = false;
588 // Insert primary selection with middle mouse
589 // if there is a local selection in the current buffer,
591 if (button == mouse_button::button2) {
592 if (paste_internally)
593 owner_->dispatch(FuncRequest(LFUN_PASTE));
595 owner_->dispatch(FuncRequest(LFUN_PASTESELECTION, "paragraph"));
596 selection_possible = false;
602 void BufferView::Pimpl::doubleClick(int /*x*/, int /*y*/, mouse_button::state button)
607 LyXText * text = bv_->getLyXText();
609 if (text->bv_owner && bv_->theLockingInset())
612 if (button == mouse_button::button1) {
613 if (text->bv_owner) {
614 screen().hideCursor();
615 screen().toggleSelection(text, bv_);
616 text->selectWord(bv_, LyXText::WHOLE_WORD_STRICT);
617 screen().toggleSelection(text, bv_, false);
619 text->selectWord(bv_, LyXText::WHOLE_WORD_STRICT);
621 // This will fit the cursor on the screen if necessary
622 update(text, BufferView::SELECT|BufferView::FITCUR);
623 workarea().haveSelection(bv_->getLyXText()->selection.set());
628 void BufferView::Pimpl::tripleClick(int /*x*/, int /*y*/, mouse_button::state button)
633 LyXText * text = bv_->getLyXText();
635 if (text->bv_owner && bv_->theLockingInset())
638 if (button == mouse_button::button1) {
639 if (text->bv_owner) {
640 screen().hideCursor();
641 screen().toggleSelection(text, bv_);
643 text->cursorHome(bv_);
644 text->selection.cursor = text->cursor;
645 text->cursorEnd(bv_);
646 text->setSelection(bv_);
647 if (text->bv_owner) {
648 screen().toggleSelection(text, bv_, false);
650 // This will fit the cursor on the screen if necessary
651 update(text, BufferView::SELECT|BufferView::FITCUR);
652 workarea().haveSelection(bv_->getLyXText()->selection.set());
657 void BufferView::Pimpl::selectionRequested()
664 LyXText * text = bv_->getLyXText();
666 if (text->selection.set() &&
667 (!bv_->text->xsel_cache.set() ||
668 text->selection.start != bv_->text->xsel_cache.start ||
669 text->selection.end != bv_->text->xsel_cache.end))
671 bv_->text->xsel_cache = text->selection;
672 sel = text->selectionAsString(bv_->buffer(), false);
673 } else if (!text->selection.set()) {
675 bv_->text->xsel_cache.set(false);
678 workarea().putClipboard(sel);
683 void BufferView::Pimpl::selectionLost()
688 bv_->getLyXText()->clearSelection();
690 bv_->text->xsel_cache.set(false);
695 void BufferView::Pimpl::workAreaButtonRelease(int x, int y,
696 mouse_button::state button)
698 // do nothing if we used the mouse wheel
699 if (!buffer_ || button == mouse_button::button4 || button == mouse_button::button5)
702 // If we hit an inset, we have the inset coordinates in these
703 // and inset_hit points to the inset. If we do not hit an
704 // inset, inset_hit is 0, and inset_x == x, inset_y == y.
705 Inset * inset_hit = checkInsetHit(bv_->text, x, y);
707 if (bv_->theLockingInset()) {
708 // We are in inset locking mode.
710 // LyX does a kind of work-area grabbing for insets.
711 // Only a ButtonPress FuncRequest outside the inset will
712 // force a insetUnlock.
713 FuncRequest cmd(bv_, LFUN_MOUSE_RELEASE, x, y, button);
714 bv_->theLockingInset()->localDispatch(cmd);
718 selection_possible = false;
720 if (button == mouse_button::button2)
724 if (button == mouse_button::button1) {
725 workarea().haveSelection(bv_->getLyXText()->selection.set());
729 owner_->view_state_changed();
730 owner_->updateMenubar();
731 owner_->updateToolbar();
733 // Did we hit an editable inset?
735 selection_possible = false;
737 // if we reach this point with a selection, it
738 // must mean we are currently selecting.
739 // But we don't want to open the inset
740 // because that is annoying for the user.
741 // So just pretend we didn't hit it.
742 // this is OK because a "kosher" ButtonRelease
743 // will follow a ButtonPress that clears
745 // Note this also fixes selection drawing
746 // problems if we end up opening an inset
747 if (bv_->getLyXText()->selection.set())
750 // CHECK fix this proper in 0.13
751 // well, maybe 13.0 !!!!!!!!!
753 // Following a ref shouldn't issue
754 // a push on the undo-stack
755 // anylonger, now that we have
756 // keybindings for following
757 // references and returning from
758 // references. IMHO though, it
759 // should be the inset's own business
760 // to push or not push on the undo
761 // stack. They don't *have* to
762 // alter the document...
764 // ...or maybe the SetCursorParUndo()
765 // below isn't necessary at all anylonger?
766 if (inset_hit->lyxCode() == Inset::REF_CODE) {
767 setCursorParUndo(bv_);
770 owner_->message(inset_hit->editMessage());
772 if (isHighlyEditableInset(inset_hit)) {
773 // Highly editable inset, like math
774 UpdatableInset *inset = (UpdatableInset *)inset_hit;
775 FuncRequest cmd(bv_, LFUN_MOUSE_RELEASE, x, y, button);
776 inset->localDispatch(cmd);
778 FuncRequest cmd(bv_, LFUN_MOUSE_RELEASE, x, y, button);
779 inset_hit->localDispatch(cmd);
780 // IMO this is a grosshack! Inset's should be changed so that
781 // they call the actions they have to do with the insetButtonRel.
782 // function and not in the edit(). This should be changed
785 #warning Please remove donot call inset->edit() here (Jug 20020812)
787 inset_hit->edit(bv_, x, y, button);
792 // Maybe we want to edit a bibitem ale970302
793 if (bv_->text->cursor.par()->bibkey) {
794 bool const is_rtl = bv_->text->cursor.par()->isRightToLeftPar(buffer_->params);
795 int const width = bibitemMaxWidth(bv_, buffer_->params.getLyXTextClass().defaultfont());
796 if ((is_rtl && x > bv_->text->workWidth(bv_)-20-width) ||
797 (!is_rtl && x < 20+width)) {
798 bv_->text->cursor.par()->bibkey->edit(bv_, 0, 0, mouse_button::none);
806 Box BufferView::Pimpl::insetDimensions(LyXText const & text,
807 LyXCursor const & cursor) const
809 Paragraph /*const*/ & par = *cursor.par();
810 pos_type const pos = cursor.pos();
812 lyx::Assert(par.getInset(pos));
814 Inset const & inset(*par.getInset(pos));
816 LyXFont const & font = text.getFont(buffer_, &par, pos);
818 int const width = inset.width(bv_, font);
819 int const inset_x = font.isVisibleRightToLeft()
820 ? (cursor.ix() - width) : cursor.ix();
823 inset_x + inset.scroll(),
825 cursor.iy() - inset.ascent(bv_, font),
826 cursor.iy() + inset.descent(bv_, font));
830 Inset * BufferView::Pimpl::checkInset(LyXText const & text,
831 LyXCursor const & cursor,
832 int & x, int & y) const
834 pos_type const pos(cursor.pos());
835 Paragraph /*const*/ & par(*cursor.par());
837 if (pos >= par.size() || !par.isInset(pos)) {
841 Inset /*const*/ * inset = par.getInset(pos);
843 if (!isEditableInset(inset)) {
847 Box b(insetDimensions(text, cursor));
849 if (!b.contained(x, y)) {
850 lyxerr[Debug::GUI] << "Missed inset at x,y " << x << "," << y
851 << " box " << b << endl;
855 text.setCursor(bv_, &par, pos, true);
858 // The origin of an inset is on the baseline
859 y -= text.cursor.iy();
865 Inset * BufferView::Pimpl::checkInsetHit(LyXText * text, int & x, int & y)
867 int y_tmp = y + text->first_y;
870 text->setCursorFromCoordinates(bv_, cursor, x, y_tmp);
872 Inset * inset = checkInset(*text, cursor, x, y_tmp);
879 // look at previous position
880 if (cursor.pos() == 0) {
885 text->setCursor(bv_, cursor, cursor.par(), cursor.pos() - 1, true);
887 inset = checkInset(*text, cursor, x, y_tmp);
895 void BufferView::Pimpl::workAreaResize()
897 static int work_area_width;
898 static int work_area_height;
900 bool const widthChange = workarea().workWidth() != work_area_width;
901 bool const heightChange = workarea().workHeight() != work_area_height;
903 // update from work area
904 work_area_width = workarea().workWidth();
905 work_area_height = workarea().workHeight();
909 // The visible LyXView need a resize
910 resizeCurrentBuffer();
912 // Remove all texts from the textcache
913 // This is not _really_ what we want to do. What
914 // we really want to do is to delete in textcache
915 // that does not have a BufferView with matching
916 // width, but as long as we have only one BufferView
917 // deleting all gives the same result.
918 if (lyxerr.debugging())
919 textcache.show(lyxerr, "Expose delete all");
921 // FIXME: this is already done in resizeCurrentBuffer() ??
922 buffer_->resizeInsets(bv_);
923 } else if (heightChange) {
924 // fitCursor() ensures we don't jump back
925 // to the start of the document on vertical
931 if (widthChange || heightChange) {
935 // always make sure that the scrollbar is sane.
937 owner_->updateLayoutChoice();
942 void BufferView::Pimpl::update()
944 if (!bv_->theLockingInset() || !bv_->theLockingInset()->nodraw()) {
945 LyXText::text_status st = bv_->text->status();
946 screen().update(bv_->text, bv_);
948 while (bv_->text->status() == LyXText::CHANGED_IN_DRAW) {
949 bv_->text->fullRebreak(bv_);
950 st = LyXText::NEED_MORE_REFRESH;
951 bv_->text->setCursor(bv_, bv_->text->cursor.par(),
952 bv_->text->cursor.pos());
953 if (bv_->text->selection.set()) {
954 bv_->text->setCursor(bv_, bv_->text->selection.start,
955 bv_->text->selection.start.par(),
956 bv_->text->selection.start.pos());
957 bv_->text->setCursor(bv_, bv_->text->selection.end,
958 bv_->text->selection.end.par(),
959 bv_->text->selection.end.pos());
962 bv_->text->status(bv_, st);
963 screen().update(bv_->text, bv_);
965 // do this here instead of in the screen::update because of
967 bv_->text->status(bv_, LyXText::UNCHANGED);
973 // Values used when calling update:
975 // -2 - update, move sel_cursor if selection, fitcursor
976 // -1 - update, move sel_cursor if selection, fitcursor, mark dirty
977 // 0 - update, move sel_cursor if selection, fitcursor
978 // 1 - update, move sel_cursor if selection, fitcursor, mark dirty
979 // 3 - update, move sel_cursor if selection
982 // a simple redraw of the parts that need refresh
984 // move sel_cursor if selection -
985 // the text's sel_cursor is moved if there is selection is progress
988 // fitCursor() is called and the scrollbar updated
991 // the buffer is marked dirty.
1000 // UPDATE_ONLY = UPDATE;
1001 // UPDATE_SELECT = UPDATE | SELECT;
1002 // UPDATE_SELECT_MOVE = UPDATE | SELECT | FITCUR;
1003 // UPDATE_SELECT_MOVE_AFTER_CHANGE = UPDATE | SELECT | FITCUR | CHANGE;
1005 // update(-3) -> update(0) -> update(0) -> update(UPDATE)
1006 // update(-2) -> update(1 + 2) -> update(3) -> update(SELECT|FITCUR)
1007 // update(-1) -> update(1 + 2 + 4) -> update(7) -> update(SELECT|FITCUR|CHANGE)
1008 // update(1) -> update(1 + 2 + 4) -> update(7) -> update(SELECT|FITCUR|CHANGE)
1009 // update(3) -> update(1) -> update(1) -> update(SELECT)
1011 void BufferView::Pimpl::update(LyXText * text, BufferView::UpdateCodes f)
1013 owner_->updateLayoutChoice();
1015 if (!text->selection.set() && (f & SELECT)) {
1016 text->selection.cursor = text->cursor;
1019 text->fullRebreak(bv_);
1021 if (text->inset_owner) {
1022 text->inset_owner->setUpdateStatus(bv_, InsetText::NONE);
1023 updateInset(text->inset_owner, false);
1033 buffer_->markDirty();
1038 // Callback for cursor timer
1039 void BufferView::Pimpl::cursorToggle()
1042 cursor_timeout.restart();
1047 extern void reapSpellchecker(void);
1050 if (!bv_->theLockingInset()) {
1051 screen().cursorToggle(bv_);
1053 bv_->theLockingInset()->toggleInsetCursor(bv_);
1056 cursor_timeout.restart();
1060 bool BufferView::Pimpl::available() const
1062 if (buffer_ && bv_->text)
1068 void BufferView::Pimpl::beforeChange(LyXText * text)
1071 text->clearSelection();
1075 void BufferView::Pimpl::savePosition(unsigned int i)
1077 if (i >= saved_positions_num)
1079 saved_positions[i] = Position(buffer_->fileName(),
1080 bv_->text->cursor.par()->id(),
1081 bv_->text->cursor.pos());
1084 str << _("Saved bookmark") << ' ' << i;
1085 owner_->message(str.str().c_str());
1090 void BufferView::Pimpl::restorePosition(unsigned int i)
1092 if (i >= saved_positions_num)
1095 string const fname = saved_positions[i].filename;
1097 beforeChange(bv_->text);
1099 if (fname != buffer_->fileName()) {
1100 Buffer * b = bufferlist.exists(fname) ?
1101 bufferlist.getBuffer(fname) :
1102 bufferlist.loadLyXFile(fname); // don't ask, just load it
1103 if (b != 0) buffer(b);
1106 Paragraph * par = buffer_->getParFromID(saved_positions[i].par_id);
1110 bv_->text->setCursor(bv_, par,
1111 min(par->size(), saved_positions[i].par_pos));
1113 update(bv_->text, BufferView::SELECT | BufferView::FITCUR);
1116 str << _("Moved to bookmark") << ' ' << i;
1117 owner_->message(str.str().c_str());
1122 bool BufferView::Pimpl::isSavedPosition(unsigned int i)
1124 if (i >= saved_positions_num)
1127 return !saved_positions[i].filename.empty();
1131 void BufferView::Pimpl::switchKeyMap()
1133 if (!lyxrc.rtl_support)
1136 LyXText * text = bv_->getLyXText();
1137 if (text->real_current_font.isRightToLeft()
1138 && !(bv_->theLockingInset()
1139 && bv_->theLockingInset()->lyxCode() == Inset::ERT_CODE))
1141 if (owner_->getIntl().keymap == Intl::PRIMARY)
1142 owner_->getIntl().KeyMapSec();
1144 if (owner_->getIntl().keymap == Intl::SECONDARY)
1145 owner_->getIntl().KeyMapPrim();
1150 void BufferView::Pimpl::insetUnlock()
1152 if (bv_->theLockingInset()) {
1153 bv_->theLockingInset()->insetUnlock(bv_);
1154 bv_->theLockingInset(0);
1160 void BufferView::Pimpl::showCursor()
1162 if (bv_->theLockingInset())
1163 bv_->theLockingInset()->showInsetCursor(bv_);
1165 screen().showCursor(bv_->text, bv_);
1169 void BufferView::Pimpl::hideCursor()
1171 if (!bv_->theLockingInset())
1172 screen().hideCursor();
1176 void BufferView::Pimpl::toggleSelection(bool b)
1178 if (bv_->theLockingInset())
1179 bv_->theLockingInset()->toggleSelection(bv_, b);
1180 screen().toggleSelection(bv_->text, bv_, b);
1184 void BufferView::Pimpl::toggleToggle()
1186 screen().toggleToggle(bv_->text, bv_);
1190 void BufferView::Pimpl::center()
1192 LyXText * t = bv_->text;
1195 int const half_height = workarea().workHeight() / 2;
1198 if (t->cursor.y() > half_height) {
1199 new_y = t->cursor.y() - half_height;
1202 // FIXME: can we do this w/o calling screen directly ?
1203 // This updates first_y but means the fitCursor() call
1204 // from the update(FITCUR) doesn't realise that we might
1205 // have moved (e.g. from GOTOPARAGRAPH), so doesn't cause
1206 // the scrollbar to be updated as it should, so we have
1207 // to do it manually. Any operation that does a center()
1208 // and also might have moved first_y must make sure to call
1209 // updateScrollbar() currently. Never mind that this is a
1210 // pretty obfuscated way of updating t->first_y
1211 screen().draw(t, bv_, new_y);
1213 update(t, BufferView::SELECT | BufferView::FITCUR);
1217 void BufferView::Pimpl::stuffClipboard(string const & stuff) const
1219 workarea().putClipboard(stuff);
1224 * Dispatch functions for actions which can be valid for BufferView->text
1225 * and/or InsetText->text!!!
1229 Inset * BufferView::Pimpl::getInsetByCode(Inset::Code code)
1232 LyXCursor cursor = bv_->getLyXText()->cursor;
1233 Buffer::inset_iterator it =
1234 find_if(Buffer::inset_iterator(
1235 cursor.par(), cursor.pos()),
1236 buffer_->inset_iterator_end(),
1237 lyx::compare_memfun(&Inset::lyxCode, code));
1238 return it != buffer_->inset_iterator_end() ? (*it) : 0;
1240 // Ok, this is a little bit too brute force but it
1241 // should work for now. Better infrastructure is comming. (Lgb)
1243 Buffer * b = bv_->buffer();
1244 LyXCursor cursor = bv_->getLyXText()->cursor;
1246 Buffer::inset_iterator beg = b->inset_iterator_begin();
1247 Buffer::inset_iterator end = b->inset_iterator_end();
1249 bool cursor_par_seen = false;
1251 for (; beg != end; ++beg) {
1252 if (beg.getPar() == cursor.par()) {
1253 cursor_par_seen = true;
1255 if (cursor_par_seen) {
1256 if (beg.getPar() == cursor.par()
1257 && beg.getPos() >= cursor.pos()) {
1259 } else if (beg.getPar() != cursor.par()) {
1266 // Now find the first inset that matches code.
1267 for (; beg != end; ++beg) {
1268 if (beg->lyxCode() == code) {
1278 void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
1280 string filename = filen;
1282 if (filename.empty()) {
1283 // Launch a file browser
1284 string initpath = lyxrc.document_path;
1287 string const trypath = owner_->buffer()->filePath();
1288 // If directory is writeable, use this as default.
1289 if (IsDirWriteable(trypath))
1293 FileDialog fileDlg(bv_->owner(),
1294 _("Select LyX document to insert"),
1296 make_pair(string(_("Documents|#o#O")),
1297 string(lyxrc.document_path)),
1298 make_pair(string(_("Examples|#E#e")),
1299 string(AddPath(system_lyxdir, "examples"))));
1301 FileDialog::Result result =
1302 fileDlg.Select(initpath,
1303 _("*.lyx| LyX Documents (*.lyx)"));
1305 if (result.first == FileDialog::Later)
1308 filename = result.second;
1310 // check selected filename
1311 if (filename.empty()) {
1312 owner_->message(_("Canceled."));
1317 // get absolute path of file and add ".lyx" to the filename if
1319 filename = FileSearch(string(), filename, "lyx");
1321 string const disp_fn(MakeDisplayPath(filename));
1324 s1 << _("Inserting document") << ' '
1325 << disp_fn << " ...";
1326 owner_->message(s1.str().c_str());
1327 bool const res = bv_->insertLyXFile(filename);
1330 str << _("Document") << ' ' << disp_fn
1331 << ' ' << _("inserted.");
1332 owner_->message(str.str().c_str());
1335 str << _("Could not insert document") << ' '
1337 owner_->message(str.str().c_str());
1342 bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
1344 lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch: action["
1345 << ev.action <<"] arg[" << ev.argument << "]" << endl;
1347 LyXTextClass const & tclass = buffer_->params.getLyXTextClass();
1349 switch (ev.action) {
1351 case LFUN_TOC_INSERT:
1353 InsetCommandParams p;
1354 p.setCmdName("tableofcontents");
1355 Inset * inset = new InsetTOC(p);
1356 if (!insertInset(inset, tclass.defaultLayoutName()))
1361 case LFUN_SCROLL_INSET:
1362 // this is not handled here as this function is only active
1363 // if we have a locking_inset and that one is (or contains)
1367 case LFUN_INSET_GRAPHICS:
1369 Inset * new_inset = new InsetGraphics;
1370 if (!insertInset(new_inset)) {
1373 // this is need because you don't use a inset->Edit()
1374 updateInset(new_inset, true);
1375 new_inset->edit(bv_);
1380 case LFUN_LAYOUT_COPY:
1381 bv_->copyEnvironment();
1384 case LFUN_LAYOUT_PASTE:
1385 bv_->pasteEnvironment();
1389 case LFUN_DEPTH_MIN:
1390 changeDepth(bv_, bv_->getLyXText(), -1);
1393 case LFUN_DEPTH_PLUS:
1394 changeDepth(bv_, bv_->getLyXText(), 1);
1398 owner_->getDialogs().setUserFreeFont();
1401 case LFUN_FILE_INSERT:
1402 MenuInsertLyXFile(ev.argument);
1405 case LFUN_FILE_INSERT_ASCII_PARA:
1406 InsertAsciiFile(bv_, ev.argument, true);
1409 case LFUN_FILE_INSERT_ASCII:
1410 InsertAsciiFile(bv_, ev.argument, false);
1414 lang(bv_, ev.argument);
1416 owner_->view_state_changed();
1421 owner_->view_state_changed();
1426 owner_->view_state_changed();
1431 owner_->view_state_changed();
1436 owner_->view_state_changed();
1441 owner_->view_state_changed();
1446 owner_->view_state_changed();
1451 owner_->view_state_changed();
1454 case LFUN_UNDERLINE:
1456 owner_->view_state_changed();
1459 case LFUN_FONT_SIZE:
1460 fontSize(bv_, ev.argument);
1461 owner_->view_state_changed();
1464 case LFUN_FONT_STATE:
1465 owner_->getLyXFunc().setMessage(currentState(bv_));
1468 case LFUN_INSERT_LABEL:
1469 MenuInsertLabel(bv_, ev.argument);
1472 case LFUN_REF_INSERT:
1473 if (ev.argument.empty()) {
1474 InsetCommandParams p("ref");
1475 owner_->getDialogs().createRef(p.getAsString());
1477 InsetCommandParams p;
1478 p.setFromString(ev.argument);
1480 InsetRef * inset = new InsetRef(p, *buffer_);
1481 if (!insertInset(inset))
1484 updateInset(inset, true);
1488 case LFUN_BOOKMARK_SAVE:
1489 savePosition(strToUnsignedInt(ev.argument));
1492 case LFUN_BOOKMARK_GOTO:
1493 restorePosition(strToUnsignedInt(ev.argument));
1498 string label = ev.argument;
1499 if (label.empty()) {
1501 static_cast<InsetRef*>(getInsetByCode(Inset::REF_CODE));
1503 label = inset->getContents();
1508 if (!label.empty()) {
1509 //bv_->savePosition(0);
1510 if (!bv_->gotoLabel(label))
1511 Alert::alert(_("Error"),
1512 _("Couldn't find this label"),
1513 _("in current document."));
1521 InsetCommandParams p;
1522 if (ev.action == LFUN_HTMLURL)
1523 p.setCmdName("htmlurl");
1525 p.setCmdName("url");
1526 owner_->getDialogs().createUrl(p.getAsString());
1530 case LFUN_INSERT_URL:
1532 InsetCommandParams p;
1533 p.setFromString(ev.argument);
1535 InsetUrl * inset = new InsetUrl(p);
1536 if (!insertInset(inset))
1539 updateInset(inset, true);
1543 case LFUN_INSET_CAPTION:
1545 // Do we have a locking inset...
1546 if (bv_->theLockingInset()) {
1547 lyxerr << "Locking inset code: "
1548 << static_cast<int>(bv_->theLockingInset()->lyxCode());
1549 InsetCaption * new_inset =
1550 new InsetCaption(buffer_->params);
1551 new_inset->setOwner(bv_->theLockingInset());
1552 new_inset->setAutoBreakRows(true);
1553 new_inset->setDrawFrame(0, InsetText::LOCKED);
1554 new_inset->setFrameColor(0, LColor::captionframe);
1555 if (insertInset(new_inset))
1556 new_inset->edit(bv_);
1563 case LFUN_TABULAR_INSERT:
1565 if (ev.argument.empty()) {
1566 owner_->getDialogs().showTabularCreate();
1572 ::sscanf(ev.argument.c_str(),"%d%d", &r, &c);
1573 InsetTabular * new_inset =
1574 new InsetTabular(*buffer_, r, c);
1576 bv_->getLyXText()->real_current_font.isRightToLeft();
1577 if (!open_new_inset(new_inset, rtl))
1583 // --- accented characters ---------------------------
1586 case LFUN_CIRCUMFLEX:
1596 case LFUN_SPECIAL_CARON:
1599 case LFUN_HUNG_UMLAUT:
1602 if (ev.argument.empty()) {
1604 owner_->getLyXFunc().handleKeyFunc(ev.action);
1606 owner_->getLyXFunc().handleKeyFunc(ev.action);
1607 owner_->getIntl().getTransManager()
1608 .TranslateAndInsert(ev.argument[0], bv_->getLyXText());
1609 update(bv_->getLyXText(),
1611 | BufferView::FITCUR
1612 | BufferView::CHANGE);
1616 case LFUN_MATH_MACRO:
1617 case LFUN_MATH_DELIM:
1618 case LFUN_INSERT_MATRIX:
1619 case LFUN_INSERT_MATH:
1620 case LFUN_MATH_IMPORT_SELECTION: // Imports LaTeX from the X selection
1621 case LFUN_MATH_DISPLAY: // Open or create a displayed math inset
1622 case LFUN_MATH_MODE: // Open or create an inlined math inset
1623 case LFUN_GREEK: // Insert a single greek letter
1624 mathDispatch(FuncRequest(bv_, ev.action, ev.argument));
1627 case LFUN_CITATION_INSERT:
1629 InsetCommandParams p;
1630 p.setFromString(ev.argument);
1632 InsetCitation * inset = new InsetCitation(p);
1633 if (!insertInset(inset))
1636 updateInset(inset, true);
1640 case LFUN_INSERT_BIBTEX:
1642 // ale970405+lasgoutt970425
1643 // The argument can be up to two tokens separated
1644 // by a space. The first one is the bibstyle.
1645 string const db = token(ev.argument, ' ', 0);
1646 string bibstyle = token(ev.argument, ' ', 1);
1647 if (bibstyle.empty())
1650 InsetCommandParams p("BibTeX", db, bibstyle);
1651 InsetBibtex * inset = new InsetBibtex(p);
1653 if (insertInset(inset)) {
1654 if (ev.argument.empty())
1661 // BibTeX data bases
1662 case LFUN_BIBDB_ADD:
1664 InsetBibtex * inset =
1665 static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
1667 inset->addDatabase(ev.argument);
1672 case LFUN_BIBDB_DEL:
1674 InsetBibtex * inset =
1675 static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
1677 inset->delDatabase(ev.argument);
1682 case LFUN_BIBTEX_STYLE:
1684 InsetBibtex * inset =
1685 static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
1687 inset->setOptions(ev.argument);
1692 case LFUN_INDEX_INSERT:
1694 string entry = ev.argument;
1696 entry = bv_->getLyXText()->getStringToIndex(bv_);
1698 if (entry.empty()) {
1699 owner_->getDialogs().createIndex();
1703 InsetIndex * inset = new InsetIndex(InsetCommandParams("index", entry));
1705 if (!insertInset(inset)) {
1708 updateInset(inset, true);
1713 case LFUN_INDEX_PRINT:
1715 InsetCommandParams p("printindex");
1716 Inset * inset = new InsetPrintIndex(p);
1717 if (!insertInset(inset, tclass.defaultLayoutName()))
1722 case LFUN_PARENTINSERT:
1724 InsetCommandParams p("lyxparent", ev.argument);
1725 Inset * inset = new InsetParent(p, *buffer_);
1726 if (!insertInset(inset, tclass.defaultLayoutName()))
1732 case LFUN_CHILD_INSERT:
1734 InsetInclude::Params p;
1735 p.cparams.setFromString(ev.argument);
1736 p.masterFilename_ = buffer_->fileName();
1738 InsetInclude * inset = new InsetInclude(p);
1739 if (!insertInset(inset))
1742 updateInset(inset, true);
1743 bv_->owner()->getDialogs().showInclude(inset);
1748 case LFUN_FLOAT_LIST:
1749 if (floatList.typeExist(ev.argument)) {
1750 Inset * inset = new InsetFloatList(ev.argument);
1751 if (!insertInset(inset, tclass.defaultLayoutName()))
1754 lyxerr << "Non-existent float type: "
1755 << ev.argument << endl;
1759 case LFUN_THESAURUS_ENTRY:
1761 string arg = ev.argument;
1764 arg = bv_->getLyXText()->selectionAsString(buffer_,
1768 if (arg.size() > 100 || arg.empty()) {
1769 // Get word or selection
1770 bv_->getLyXText()->selectWordWhenUnderCursor(bv_, LyXText::WHOLE_WORD);
1771 arg = bv_->getLyXText()->selectionAsString(buffer_, false);
1772 // FIXME: where is getLyXText()->unselect(bv_) ?
1776 bv_->owner()->getDialogs().showThesaurus(arg);
1780 case LFUN_UNKNOWN_ACTION:
1781 ev.errorMessage(N_("Unknown function!"));
1785 FuncRequest cmd = ev;
1787 return bv_->getLyXText()->dispatch(cmd);
1794 // Open and lock an updatable inset
1795 bool BufferView::Pimpl::open_new_inset(UpdatableInset * new_inset, bool behind)
1797 LyXText * lt = bv_->getLyXText();
1801 if (!insertInset(new_inset)) {
1805 new_inset->edit(bv_, !behind);
1810 bool BufferView::Pimpl::insertInset(Inset * inset, string const & lout)
1812 // if we are in a locking inset we should try to insert the
1813 // inset there otherwise this is a illegal function now
1814 if (bv_->theLockingInset()) {
1815 if (bv_->theLockingInset()->insetAllowed(inset))
1816 return bv_->theLockingInset()->insertInset(bv_, inset);
1820 // not quite sure if we want this...
1821 setCursorParUndo(bv_);
1824 beforeChange(bv_->text);
1825 if (!lout.empty()) {
1826 update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
1827 bv_->text->breakParagraph(bv_);
1828 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1830 if (!bv_->text->cursor.par()->empty()) {
1831 bv_->text->cursorLeft(bv_);
1833 bv_->text->breakParagraph(bv_);
1834 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1838 LyXTextClass const & tclass =
1839 buffer_->params.getLyXTextClass();
1840 bool hasLayout = tclass.hasLayout(lres);
1841 string lay = tclass.defaultLayoutName();
1843 if (hasLayout != false) {
1847 // layout not fount using default
1848 lay = tclass.defaultLayoutName();
1851 bv_->text->setLayout(bv_, lay);
1853 bv_->text->setParagraph(bv_, 0, 0,
1855 VSpace(VSpace::NONE), VSpace(VSpace::NONE),
1860 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1863 bv_->text->insertInset(bv_, inset);
1864 update(bv_->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
1871 void BufferView::Pimpl::updateInset(Inset * inset, bool mark_dirty)
1873 if (!inset || !available())
1876 // first check for locking insets
1877 if (bv_->theLockingInset()) {
1878 if (bv_->theLockingInset() == inset) {
1879 if (bv_->text->updateInset(bv_, inset)) {
1882 buffer_->markDirty();
1887 } else if (bv_->theLockingInset()->updateInsetInInset(bv_, inset)) {
1888 if (bv_->text->updateInset(bv_, bv_->theLockingInset())) {
1891 buffer_->markDirty();
1899 // then check if the inset is a top_level inset (has no owner)
1900 // if yes do the update as always otherwise we have to update the
1901 // toplevel inset where this inset is inside
1902 Inset * tl_inset = inset;
1903 while (tl_inset->owner())
1904 tl_inset = tl_inset->owner();
1906 if (tl_inset == inset) {
1907 update(bv_->text, BufferView::UPDATE);
1908 if (bv_->text->updateInset(bv_, inset)) {
1912 | BufferView::FITCUR
1913 | BufferView::CHANGE);
1915 update(bv_->text, SELECT);
1919 } else if (static_cast<UpdatableInset *>(tl_inset)
1920 ->updateInsetInInset(bv_, inset))
1922 if (bv_->text->updateInset(bv_, tl_inset)) {