X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.C;h=29ad13b273bf25b7c66faf71ff4e2a3b177c8199;hb=e7f4618bcce770369cf46335c2c7f0164b4b8857;hp=6760ac736926c2504af1c1cd1de616f6e35b1c69;hpb=f5c6da2b51a46e2e36919d02d0db0bb6ea3abe36;p=lyx.git diff --git a/src/BufferView.C b/src/BufferView.C index 6760ac7369..29ad13b273 100644 --- a/src/BufferView.C +++ b/src/BufferView.C @@ -20,6 +20,7 @@ #include "buffer_funcs.h" #include "bufferlist.h" #include "bufferparams.h" +#include "bufferview_funcs.h" #include "coordcache.h" #include "CutAndPaste.h" #include "debug.h" @@ -88,7 +89,6 @@ using support::fileSearch; using support::isDirWriteable; using support::isFileReadable; using support::makeDisplayPath; -using support::makeAbsPath; using support::package; using std::distance; @@ -125,7 +125,7 @@ BufferView::BufferView() : width_(0), height_(0), buffer_(0), wh_(0), cursor_(*this), multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0), - intl_(new Intl) + intl_(new Intl), last_inset_(0) { xsel_cache_.set = false; intl_->initKeyMapper(lyxrc.use_kbmap); @@ -154,6 +154,19 @@ void BufferView::setBuffer(Buffer * b) // to this buffer later on. buffer_->saveCursor(cursor_.selectionBegin(), cursor_.selectionEnd()); + // update bookmark pit of the current buffer before switch + for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) { + BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(i); + if (buffer()->fileName() != bm.filename.absFilename()) + continue; + // if par_id or pit has been changed, reset par_pit and par_id + // see http://bugzilla.lyx.org/show_bug.cgi?id=3092 + pit_type new_pit; + int new_id; + boost::tie(new_pit, new_id) = moveToPosition(bm.par_pit, bm.par_id, bm.par_pos); + if (bm.par_pit != new_pit || bm.par_id != new_id) + const_cast(bm).setPos(new_pit, new_id); + } // current buffer is going to be switched-off, save cursor pos LyX::ref().session().lastFilePos().save(FileName(buffer_->fileName()), boost::tie(cursor_.pit(), cursor_.pos()) ); @@ -187,7 +200,6 @@ void BufferView::setBuffer(Buffer * b) << "Buffer addr: " << buffer_ << endl; cursor_.push(buffer_->inset()); cursor_.resetAnchor(); - buffer_->text().init(this); buffer_->text().setCurrentFont(cursor_); if (buffer_->getCursor().size() > 0 && buffer_->getAnchor().size() > 0) @@ -196,6 +208,8 @@ void BufferView::setBuffer(Buffer * b) cursor_.resetAnchor(); cursor_.setCursor(buffer_->getCursor().asDocIterator(&(buffer_->inset()))); cursor_.setSelection(); + // do not set selection to the new buffer because we + // only paste recent selection. } } @@ -256,27 +270,17 @@ bool BufferView::loadLyXFile(FileName const & filename, bool tolastfiles) // Send the "errors" signal in case of parsing errors b->errors("Parse"); + // Update the labels and section numbering. + updateLabels(*buffer_); // scroll to the position when the file was last closed if (lyxrc.use_lastfilepos) { pit_type pit; pos_type pos; boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(filename); - // I am not sure how to separate the following part to a function - // so I will leave this to Lars. - // - // check pit since the document may be externally changed. - if ( static_cast(pit) < b->paragraphs().size() ) { - ParIterator it = b->par_iterator_begin(); - ParIterator const end = b->par_iterator_end(); - for (; it != end; ++it) - if (it.pit() == pit) { - // restored pos may be bigger than it->size - setCursor(makeDocIterator(it, min(pos, it->size()))); - // No need to update the metrics if fitCursor returns false. - if (fitCursor()) - updateMetrics(false); - break; - } + // if successfully move to pit (returned par_id is not zero), update metrics + if (moveToPosition(pit, 0, pos).get<1>()) { + if (fitCursor()) + updateMetrics(false); } } @@ -287,13 +291,6 @@ bool BufferView::loadLyXFile(FileName const & filename, bool tolastfiles) } -void BufferView::reload() -{ - if (theBufferList().close(buffer_, false)) - loadLyXFile(FileName(buffer_->fileName())); -} - - void BufferView::resize() { if (!buffer_) @@ -301,8 +298,7 @@ void BufferView::resize() lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION << endl; - buffer_->text().init(this); - update(); + updateMetrics(false); switchKeyMap(); } @@ -334,8 +330,12 @@ bool BufferView::multiParSel() } -std::pair BufferView::update(Update::flags flags) +bool BufferView::update(Update::flags flags) { + // last_inset_ points to the last visited inset. This pointer may become + // invalid because of keyboard editing. Since all such operations + // causes screen update(), I reset last_inset_ to avoid such a problem. + last_inset_ = 0; // This is close to a hot-path. if (lyxerr.debugging(Debug::DEBUG)) { lyxerr[Debug::DEBUG] @@ -348,7 +348,7 @@ std::pair BufferView::update(Update::flags flags) // Check needed to survive LyX startup if (!buffer_) - return make_pair(false, false); + return false; if (lyxerr.debugging(Debug::WORKAREA)) { lyxerr[Debug::WORKAREA] << "BufferView::update" << std::endl; @@ -363,16 +363,31 @@ std::pair BufferView::update(Update::flags flags) // Case when no explicit update is requested. if (!flags) { - // no need to do anything. - return make_pair(false, false); + // no need to redraw anything. + metrics_info_.update_strategy = NoScreenUpdate; + return false; + } + + if (flags == Update::Decoration) { + metrics_info_.update_strategy = DecorationUpdate; + return true; } - if (flags == Update::FitCursor) { + if (flags == Update::FitCursor + || flags == (Update::Decoration | Update::FitCursor)) { bool const fit_cursor = fitCursor(); - if (fit_cursor) + // tell the frontend to update the screen if needed. + if (fit_cursor) { updateMetrics(false); - // tell the frontend to update the screen. - return make_pair(fit_cursor, false); + return true; + } + if (flags & Update::Decoration) { + metrics_info_.update_strategy = DecorationUpdate; + return true; + } + // no screen update is needed. + metrics_info_.update_strategy = NoScreenUpdate; + return false; } bool full_metrics = flags & Update::Force; @@ -386,7 +401,7 @@ std::pair BufferView::update(Update::flags flags) updateMetrics(false); // tell the frontend to update the screen. - return make_pair(true, single_par); + return true; } @@ -400,6 +415,8 @@ void BufferView::updateScrollbar() } LyXText & t = buffer_->text(); + TextMetrics & tm = text_metrics_[&t]; + int const parsize = int(t.paragraphs().size() - 1); if (anchor_ref_ > parsize) { anchor_ref_ = parsize; @@ -420,13 +437,14 @@ void BufferView::updateScrollbar() // estimated average paragraph height: if (wh_ == 0) wh_ = height_ / 4; - int h = t.getPar(anchor_ref_).height(); + + int h = tm.parMetrics(anchor_ref_).height(); // Normalize anchor/offset (MV): while (offset_ref_ > h && anchor_ref_ < parsize) { anchor_ref_++; offset_ref_ -= h; - h = t.getPar(anchor_ref_).height(); + h = tm.parMetrics(anchor_ref_).height(); } // Look at paragraph heights on-screen int sumh = 0; @@ -434,7 +452,7 @@ void BufferView::updateScrollbar() for (pit_type pit = anchor_ref_; pit <= parsize; ++pit) { if (sumh > height_) break; - int const h2 = t.getPar(pit).height(); + int const h2 = tm.parMetrics(pit).height(); sumh += h2; nh++; } @@ -467,14 +485,16 @@ void BufferView::scrollDocView(int value) return; LyXText & t = buffer_->text(); + TextMetrics & tm = text_metrics_[&t]; float const bar = value / float(wh_ * t.paragraphs().size()); anchor_ref_ = int(bar * t.paragraphs().size()); if (anchor_ref_ > int(t.paragraphs().size()) - 1) anchor_ref_ = int(t.paragraphs().size()) - 1; - t.redoParagraph(*this, anchor_ref_); - int const h = t.getPar(anchor_ref_).height(); + + tm.redoParagraph(anchor_ref_); + int const h = tm.parMetrics(anchor_ref_).height(); offset_ref_ = int((bar * t.paragraphs().size() - anchor_ref_) * h); updateMetrics(false); } @@ -482,6 +502,9 @@ void BufferView::scrollDocView(int value) void BufferView::setCursorFromScrollbar() { + if (!buffer_) + return; + LyXText & t = buffer_->text(); int const height = 2 * defaultRowHeight(); @@ -493,10 +516,16 @@ void BufferView::setCursorFromScrollbar() switch (st) { case bv_funcs::CUR_ABOVE: + // We reset the cursor because bv_funcs::status() does not + // work when the cursor is within mathed. + cur.reset(buffer_->inset()); t.setCursorFromCoordinates(cur, 0, first); cur.clearSelection(); break; case bv_funcs::CUR_BELOW: + // We reset the cursor because bv_funcs::status() does not + // work when the cursor is within mathed. + cur.reset(buffer_->inset()); t.setCursorFromCoordinates(cur, 0, last); cur.clearSelection(); break; @@ -525,6 +554,7 @@ void BufferView::saveBookmark(bool persistent) { LyX::ref().session().bookmarks().save( FileName(buffer_->fileName()), + cursor_.pit(), cursor_.paragraph().id(), cursor_.pos(), persistent @@ -535,15 +565,31 @@ void BufferView::saveBookmark(bool persistent) } -void BufferView::moveToPosition(int par_id, pos_type par_pos) +boost::tuple BufferView::moveToPosition(pit_type par_pit, int par_id, pos_type par_pos) { cursor_.clearSelection(); - ParIterator par = buffer_->getParFromID(par_id); - if (par == buffer_->par_iterator_end()) - return; - - setCursor(makeDocIterator(par, min(par->size(), par_pos))); + // if a valid par_id is given, try it first + if (par_id > 0) { + ParIterator par = buffer_->getParFromID(par_id); + if (par != buffer_->par_iterator_end()) { + setCursor(makeDocIterator(par, min(par->size(), par_pos))); + return boost::make_tuple(cursor_.pit(), par_id); + } + } + // if par_id == 0, or searching through par_id failed + if (static_cast(par_pit) < buffer_->paragraphs().size()) { + ParIterator it = buffer_->par_iterator_begin(); + ParIterator const end = buffer_->par_iterator_end(); + for (; it != end; ++it) + if (it.pit() == par_pit) { + // restored pos may be bigger than it->size + setCursor(makeDocIterator(it, min(par_pos, it->size()))); + return boost::make_tuple(par_pit, it->id()); + } + } + // both methods fail + return boost::make_tuple(pit_type(0), 0); } @@ -552,7 +598,7 @@ void BufferView::switchKeyMap() if (!lyxrc.rtl_support) return; - if (getLyXText()->real_current_font.isRightToLeft()) { + if (cursor_.innerText()->real_current_font.isRightToLeft()) { if (intl_->keymap == Intl::PRIMARY) intl_->keyMapSec(); } else { @@ -571,12 +617,13 @@ int BufferView::workWidth() const void BufferView::center() { CursorSlice & bot = cursor_.bottom(); + TextMetrics & tm = text_metrics_[bot.text()]; pit_type const pit = bot.pit(); - bot.text()->redoParagraph(*this, pit); - Paragraph const & par = bot.text()->paragraphs()[pit]; + tm.redoParagraph(pit); + ParagraphMetrics const & pm = tm.parMetrics(pit); anchor_ref_ = pit; offset_ref_ = bv_funcs::coordOffset(*this, cursor_, cursor_.boundary()).y_ - + par.ascent() - height_ / 2; + + pm.ascent() - height_ / 2; } @@ -593,8 +640,8 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) flag.enabled(!buffer_->redostack().empty()); break; case LFUN_FILE_INSERT: - case LFUN_FILE_INSERT_ASCII_PARA: - case LFUN_FILE_INSERT_ASCII: + case LFUN_FILE_INSERT_PLAINTEXT_PARA: + case LFUN_FILE_INSERT_PLAINTEXT: case LFUN_BOOKMARK_SAVE: // FIXME: Actually, these LFUNS should be moved to LyXText flag.enabled(cursor_.inTexted()); @@ -635,8 +682,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_CHANGES_OUTPUT: { OutputParams runparams; - LaTeXFeatures features(*buffer_, buffer_->params(), runparams); - flag.enabled(buffer_ && features.isAvailable("dvipost")); + flag.enabled(buffer_ && LaTeXFeatures::isAvailable("dvipost")); flag.setOnOff(buffer_->params().outputChanges); break; } @@ -665,7 +711,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) } -bool BufferView::dispatch(FuncRequest const & cmd) +Update::flags BufferView::dispatch(FuncRequest const & cmd) { //lyxerr << BOOST_CURRENT_FUNCTION // << [ cmd = " << cmd << "]" << endl; @@ -679,30 +725,34 @@ bool BufferView::dispatch(FuncRequest const & cmd) << " button[" << cmd.button() << ']' << endl; + // FIXME: this should not be possible. + if (!buffer_) + return Update::None; + LCursor & cur = cursor_; + // Default Update flags. + Update::flags updateFlags = Update::Force | Update::FitCursor; switch (cmd.action) { case LFUN_UNDO: - if (buffer_) { - cur.message(_("Undo")); - cur.clearSelection(); - if (!textUndo(*this)) - cur.message(_("No further undo information")); - update(); - switchKeyMap(); + cur.message(_("Undo")); + cur.clearSelection(); + if (!textUndo(*this)) { + cur.message(_("No further undo information")); + updateFlags = Update::None; } + switchKeyMap(); break; case LFUN_REDO: - if (buffer_) { - cur.message(_("Redo")); - cur.clearSelection(); - if (!textRedo(*this)) - cur.message(_("No further redo information")); - update(); - switchKeyMap(); + cur.message(_("Redo")); + cur.clearSelection(); + if (!textRedo(*this)) { + cur.message(_("No further redo information")); + updateFlags = Update::None; } + switchKeyMap(); break; case LFUN_FILE_INSERT: @@ -710,18 +760,18 @@ bool BufferView::dispatch(FuncRequest const & cmd) menuInsertLyXFile(to_utf8(cmd.argument())); break; - case LFUN_FILE_INSERT_ASCII_PARA: + case LFUN_FILE_INSERT_PLAINTEXT_PARA: // FIXME UNICODE - insertAsciiFile(this, to_utf8(cmd.argument()), true); + insertPlaintextFile(this, to_utf8(cmd.argument()), true); break; - case LFUN_FILE_INSERT_ASCII: + case LFUN_FILE_INSERT_PLAINTEXT: // FIXME UNICODE - insertAsciiFile(this, to_utf8(cmd.argument()), false); + insertPlaintextFile(this, to_utf8(cmd.argument()), false); break; case LFUN_FONT_STATE: - cur.message(from_utf8(cur.currentState())); + cur.message(cur.currentState()); break; case LFUN_BOOKMARK_SAVE: @@ -764,13 +814,13 @@ bool BufferView::dispatch(FuncRequest const & cmd) if (b == buffer_) { // Set the cursor setCursor(makeDocIterator(par, 0)); - update(); switchKeyMap(); } else { // Switch to other buffer view and resend cmd theLyXFunc().dispatch(FuncRequest( LFUN_BUFFER_SWITCH, b->fileName())); theLyXFunc().dispatch(cmd); + updateFlags = Update::None; } break; } @@ -814,10 +864,9 @@ bool BufferView::dispatch(FuncRequest const & cmd) buffer_->params().trackChanges = !buffer_->params().trackChanges; break; - case LFUN_CHANGES_OUTPUT: { + case LFUN_CHANGES_OUTPUT: buffer_->params().outputChanges = !buffer_->params().outputChanges; break; - } case LFUN_CHANGE_NEXT: findNextChange(this); @@ -828,26 +877,24 @@ bool BufferView::dispatch(FuncRequest const & cmd) showDialog("changes"); break; - case LFUN_ALL_CHANGES_ACCEPT: { + case LFUN_ALL_CHANGES_ACCEPT: + // select complete document cursor_.reset(buffer_->inset()); -#ifdef WITH_WARNINGS -#warning FIXME changes -#endif - while (findNextChange(this)) - getLyXText()->acceptChange(cursor_); - update(); + cursor_.selHandle(true); + buffer_->text().cursorBottom(cursor_); + // accept everything in a single step to support atomic undo + buffer_->text().acceptOrRejectChanges(cursor_, LyXText::ACCEPT); break; - } - case LFUN_ALL_CHANGES_REJECT: { + case LFUN_ALL_CHANGES_REJECT: + // select complete document cursor_.reset(buffer_->inset()); -#ifdef WITH_WARNINGS -#warning FIXME changes -#endif - while (findNextChange(this)) - getLyXText()->rejectChange(cursor_); + cursor_.selHandle(true); + buffer_->text().cursorBottom(cursor_); + // reject everything in a single step to support atomic undo + // Note: reject does not work recursively; the user may have to repeat the operation + buffer_->text().acceptOrRejectChanges(cursor_, LyXText::REJECT); break; - } case LFUN_WORD_FIND: find(this, cmd); @@ -970,10 +1017,10 @@ bool BufferView::dispatch(FuncRequest const & cmd) } default: - return false; + updateFlags = Update::None; } - return true; + return updateFlags; } @@ -1006,28 +1053,33 @@ void BufferView::clearSelection() { if (buffer_) { cursor_.clearSelection(); + // Clear the selection buffer. Otherwise a subsequent + // middle-mouse-button paste would use the selection buffer, + // not the more current external selection. + cap::clearSelection(); xsel_cache_.set = false; + // The buffer did not really change, but this causes the + // redraw we need because we cleared the selection above. + buffer_->changed(); } } void BufferView::workAreaResize(int width, int height) { - bool const widthChange = width != width_; - bool const heightChange = height != height_; - // Update from work area width_ = width; height_ = height; + // The complete text metrics will be redone. + text_metrics_.clear(); + if (buffer_) resize(); - - update(); } -std::pair BufferView::workAreaDispatch(FuncRequest const & cmd0) +bool BufferView::workAreaDispatch(FuncRequest const & cmd0) { //lyxerr << BOOST_CURRENT_FUNCTION << "[ cmd0 " << cmd0 << "]" << endl; @@ -1037,7 +1089,7 @@ std::pair BufferView::workAreaDispatch(FuncRequest const & cmd0) // E.g. Qt mouse press when no buffer if (!buffer_) - return make_pair(false, false); + return false; LCursor cur(*this); cur.push(buffer_->inset()); @@ -1055,27 +1107,51 @@ std::pair BufferView::workAreaDispatch(FuncRequest const & cmd0) //lyxerr << BOOST_CURRENT_FUNCTION // << " * created temp cursor:" << cur << endl; - // NOTE: eidtXY returns the top level inset of nested insets. If you happen + // NOTE: editXY returns the top level inset of nested insets. If you happen // to move from a text (inset=0) to a text inside an inset (e.g. an opened // footnote inset, again inset=0), that inset will not be redrawn. - static InsetBase * last_inset = NULL; if (cmd.action == LFUN_MOUSE_MOTION && cmd.button() == mouse_button::none) { - bool need_update = false; + bool need_redraw = false; - if (inset != last_inset) { - if (last_inset) - need_update |= last_inset->setMouseHover(false); + if (inset != last_inset_) { + if (last_inset_) + need_redraw |= last_inset_->setMouseHover(false); if (inset) - need_update |= inset->setMouseHover(true); - last_inset = inset; + need_redraw |= inset->setMouseHover(true); + last_inset_ = inset; } - // if in singlepar mode, update to get a full screen repaint. - // otherwise, buttons outside of the current paragraph will not be redrawn. - if (need_update && metrics_info_.singlepar) - update(); + + // if last metrics update was in singlepar mode, WorkArea::redraw() will + // not expose the button for redraw. We adjust here the metrics dimension + // to enable a full redraw. + // FIXME: It is possible to redraw only the area around the button! + if (need_redraw + && metrics_info_.update_strategy == SingleParUpdate) { + // FIXME: It should be possible to redraw only the area around + // the button by doing this: + // + //metrics_info_.singlepar = false; + //metrics_info_.y1 = ymin of button; + //metrics_info_.y2 = ymax of button; + // + // Unfortunately, rowpainter.C:paintText() does not distinguish + // between background updates and text updates. So we use the hammer + // solution for now. We could also avoid the updateMetrics() below + // by using the first and last pit of the CoordCache. Have a look + // at LyXText::getPitNearY() to see what I mean. + // + //metrics_info_.pit1 = first pit of CoordCache; + //metrics_info_.pit2 = last pit of CoordCache; + //metrics_info_.singlepar = false; + //metrics_info_.y1 = 0; + //metrics_info_.y2 = height_; + // + updateMetrics(false); + } + // This event (moving without mouse click) is not passed further. // This should be changed if it is further utilized. - return make_pair(need_update, need_update); + return need_redraw; } // Put anchor at the same position. @@ -1098,8 +1174,7 @@ std::pair BufferView::workAreaDispatch(FuncRequest const & cmd0) if (cur.result().dispatched() && cur.result().update()) return update(cur.result().update()); - // When the above and the inner function are fixed, we can do this: - return make_pair(false, false); + return false; } @@ -1120,8 +1195,6 @@ void BufferView::scroll(int /*lines*/) // // scrollDocView(new_top_y); // -// // Update the scrollbar. -// workArea_->setScrollbarParams(t->height(), top_y(), defaultRowHeight());} } @@ -1153,19 +1226,27 @@ void BufferView::gotoLabel(docstring const & label) } -LyXText * BufferView::getLyXText() +TextMetrics const & BufferView::textMetrics(LyXText const * t) const +{ + return const_cast(this)->textMetrics(t); +} + + +TextMetrics & BufferView::textMetrics(LyXText const * t) { - LyXText * text = cursor_.innerText(); - BOOST_ASSERT(text); - return text; + TextMetricsCache::iterator tmc_it = text_metrics_.find(t); + if (tmc_it == text_metrics_.end()) { + tmc_it = text_metrics_.insert( + make_pair(t, TextMetrics(this, const_cast(t)))).first; + } + return tmc_it->second; } -LyXText const * BufferView::getLyXText() const +ParagraphMetrics const & BufferView::parMetrics(LyXText const * t, + pit_type pit) const { - LyXText const * text = cursor_.innerText(); - BOOST_ASSERT(text); - return text; + return textMetrics(t).parMetrics(pit); } @@ -1186,7 +1267,31 @@ void BufferView::setCursor(DocIterator const & dit) } -void BufferView::mouseSetCursor(LCursor & cur) +bool BufferView::checkDepm(LCursor & cur, LCursor & old) +{ + // Would be wrong to delete anything if we have a selection. + if (cur.selection()) + return false; + + bool need_anchor_change = false; + bool changed = cursor_.text()->deleteEmptyParagraphMechanism(cur, old, + need_anchor_change); + + if (need_anchor_change) + cur.resetAnchor(); + + if (!changed) + return false; + + updateLabels(*buffer_); + + updateMetrics(false); + buffer_->changed(); + return true; +} + + +bool BufferView::mouseSetCursor(LCursor & cur) { BOOST_ASSERT(&cur.bv() == this); @@ -1197,14 +1302,31 @@ void BufferView::mouseSetCursor(LCursor & cur) // do the dEPM magic if needed // FIXME: move this to InsetText::notifyCursorLeaves? + bool update = false; if (!badcursor && cursor_.inTexted()) - cursor_.text()->deleteEmptyParagraphMechanism(cur, cursor_); + checkDepm(cur, cursor_); + + // if the cursor was in an empty script inset and the new + // position is in the nucleus of the inset, notifyCursorLeaves + // will kill the script inset itself. So we check all the + // elements of the cursor to make sure that they are correct. + // For an example, see bug 2933: + // http://bugzilla.lyx.org/show_bug.cgi?id=2933 + // The code below could maybe be moved to a DocIterator method. + //lyxerr << "cur before " << cur <text(); + TextMetrics & tm = textMetrics(&buftext); pit_type size = int(buftext.paragraphs().size()); if (anchor_ref_ > int(buftext.paragraphs().size() - 1)) { anchor_ref_ = int(buftext.paragraphs().size() - 1); offset_ref_ = 0; } + + // If the paragraph metrics has changed, we can not + // use the singlepar optimisation. + if (singlepar + // In Single Paragraph mode, rebreak only + // the (main text, not inset!) paragraph containing the cursor. + // (if this paragraph contains insets etc., rebreaking will + // recursively descend) + && tm.redoParagraph(cursor_.bottom().pit())) + singlepar = false; pit_type const pit = anchor_ref_; int pit1 = pit; int pit2 = pit; size_t const npit = buftext.paragraphs().size(); - // Rebreak anchor paragraph. In Single Paragraph mode, rebreak only - // the (main text, not inset!) paragraph containing the cursor. - // (if this paragraph contains insets etc., rebreaking will - // recursively descend) - if (!singlepar || pit == cursor_.bottom().pit()) - buftext.redoParagraph(*this, pit); - int y0 = buftext.getPar(pit).ascent() - offset_ref_; + // Rebreak anchor paragraph. + if (!singlepar) + tm.redoParagraph(pit); + + // Clear out the position cache in case of full screen redraw. + if (!singlepar) + coord_cache_.clear(); + + int y0 = tm.parMetrics(pit).ascent() - offset_ref_; - // Redo paragraphs above anchor if necessary; again, in Single Par - // mode, only if we encounter the (main text) one having the cursor. + // Redo paragraphs above anchor if necessary. int y1 = y0; while (y1 > 0 && pit1 > 0) { - y1 -= buftext.getPar(pit1).ascent(); + y1 -= tm.parMetrics(pit1).ascent(); --pit1; - if (!singlepar || pit1 == cursor_.bottom().pit()) - buftext.redoParagraph(*this, pit1); - y1 -= buftext.getPar(pit1).descent(); + if (!singlepar) + tm.redoParagraph(pit1); + y1 -= tm.parMetrics(pit1).descent(); } // Take care of ascent of first line - y1 -= buftext.getPar(pit1).ascent(); + y1 -= tm.parMetrics(pit1).ascent(); // Normalize anchor for next time anchor_ref_ = pit1; @@ -1302,34 +1434,33 @@ void BufferView::updateMetrics(bool singlepar) anchor_ref_ = 0; } - // Redo paragraphs below the anchor if necessary. Single par mode: - // only the one containing the cursor if encountered. + // Redo paragraphs below the anchor if necessary. int y2 = y0; while (y2 < height_ && pit2 < int(npit) - 1) { - y2 += buftext.getPar(pit2).descent(); + y2 += tm.parMetrics(pit2).descent(); ++pit2; - if (!singlepar || pit2 == cursor_.bottom().pit()) - buftext.redoParagraph(*this, pit2); - y2 += buftext.getPar(pit2).ascent(); + if (!singlepar) + tm.redoParagraph(pit2); + y2 += tm.parMetrics(pit2).ascent(); } // Take care of descent of last line - y2 += buftext.getPar(pit2).descent(); + y2 += tm.parMetrics(pit2).descent(); // The coordinates of all these paragraphs are correct, cache them int y = y1; CoordCache::InnerParPosCache & parPos = coord_cache_.parPos()[&buftext]; for (pit_type pit = pit1; pit <= pit2; ++pit) { - Paragraph const & par = buftext.getPar(pit); - y += par.ascent(); + ParagraphMetrics const & pm = tm.parMetrics(pit); + y += pm.ascent(); parPos[pit] = Point(0, y); if (singlepar && pit == cursor_.bottom().pit()) { // In Single Paragraph mode, collect here the // y1 and y2 of the (one) paragraph the cursor is in - y1 = y - par.ascent(); - y2 = y + par.descent(); + y1 = y - pm.ascent(); + y2 = y + pm.descent(); } - y += par.descent(); + y += pm.descent(); } if (singlepar) { @@ -1349,7 +1480,8 @@ void BufferView::updateMetrics(bool singlepar) << "size: " << size << endl; - metrics_info_ = ViewMetricsInfo(pit1, pit2, y1, y2, singlepar, size); + metrics_info_ = ViewMetricsInfo(pit1, pit2, y1, y2, + singlepar? SingleParUpdate: FullScreenUpdate, size); if (lyxerr.debugging(Debug::WORKAREA)) { lyxerr[Debug::WORKAREA] << "BufferView::updateMetrics" << endl; @@ -1371,7 +1503,7 @@ void BufferView::menuInsertLyXFile(string const & filenm) if (buffer_) { string const trypath = buffer_->filePath(); // If directory is writeable, use this as default. - if (isDirWriteable(trypath)) + if (isDirWriteable(FileName(trypath))) initpath = trypath; } @@ -1427,5 +1559,4 @@ void BufferView::menuInsertLyXFile(string const & filenm) resize(); } - } // namespace lyx