X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.C;h=ff3b47924018f876f07d04a52d8774abce6ac1c8;hb=0da3d53269a49c66b24615d24e20e441dcf7c07e;hp=d5adcc3bf0e9733a355fa3e80da4900b179a08b5;hpb=57609ac606f098a70a800491b487b24505218b04;p=lyx.git diff --git a/src/BufferView.C b/src/BufferView.C index d5adcc3bf0..ff3b479240 100644 --- a/src/BufferView.C +++ b/src/BufferView.C @@ -63,6 +63,7 @@ #include "frontends/Alert.h" #include "frontends/FileDialog.h" #include "frontends/FontMetrics.h" +#include "frontends/Selection.h" #include "graphics/Previews.h" @@ -154,6 +155,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 +201,6 @@ void BufferView::setBuffer(Buffer * b) << "Buffer addr: " << buffer_ << endl; cursor_.push(buffer_->inset()); cursor_.resetAnchor(); - updateLabels(*buffer_); buffer_->text().setCurrentFont(cursor_); if (buffer_->getCursor().size() > 0 && buffer_->getAnchor().size() > 0) @@ -196,6 +209,7 @@ void BufferView::setBuffer(Buffer * b) cursor_.resetAnchor(); cursor_.setCursor(buffer_->getCursor().asDocIterator(&(buffer_->inset()))); cursor_.setSelection(); + theSelection().haveSelection(cursor_.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_) @@ -367,15 +364,30 @@ bool BufferView::update(Update::flags flags) // Case when no explicit update is requested. if (!flags) { // no need to redraw anything. + metrics_info_.update_strategy = NoScreenUpdate; return false; } - if (flags == Update::FitCursor) { + if (flags == Update::Decoration) { + metrics_info_.update_strategy = DecorationUpdate; + return true; + } + + if (flags == Update::FitCursor + || flags == (Update::Decoration | Update::FitCursor)) { bool const fit_cursor = fitCursor(); - if (fit_cursor) - updateMetrics(false); // tell the frontend to update the screen if needed. - return fit_cursor; + if (fit_cursor) { + updateMetrics(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; @@ -490,6 +502,9 @@ void BufferView::scrollDocView(int value) void BufferView::setCursorFromScrollbar() { + if (!buffer_) + return; + LyXText & t = buffer_->text(); int const height = 2 * defaultRowHeight(); @@ -501,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; @@ -533,6 +554,7 @@ void BufferView::saveBookmark(bool persistent) { LyX::ref().session().bookmarks().save( FileName(buffer_->fileName()), + cursor_.pit(), cursor_.paragraph().id(), cursor_.pos(), persistent @@ -543,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); } @@ -602,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()); @@ -674,7 +712,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; @@ -688,30 +726,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: @@ -719,14 +761,14 @@ 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: @@ -773,13 +815,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; } @@ -823,10 +865,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); @@ -843,8 +884,7 @@ bool BufferView::dispatch(FuncRequest const & cmd) #warning FIXME changes #endif while (findNextChange(this)) - getLyXText()->acceptChange(cursor_); - update(); + getLyXText()->acceptOrRejectChanges(cursor_, LyXText::ACCEPT); break; } @@ -854,7 +894,7 @@ bool BufferView::dispatch(FuncRequest const & cmd) #warning FIXME changes #endif while (findNextChange(this)) - getLyXText()->rejectChange(cursor_); + getLyXText()->acceptOrRejectChanges(cursor_, LyXText::REJECT); break; } @@ -979,10 +1019,10 @@ bool BufferView::dispatch(FuncRequest const & cmd) } default: - return false; + updateFlags = Update::None; } - return true; + return updateFlags; } @@ -1016,20 +1056,20 @@ void BufferView::clearSelection() if (buffer_) { cursor_.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) { - // A resize is triggered whenever a window gets focus, - // because of the shared rows() of a buffer in multiple - // buffer views. - // Update from work area width_ = width; height_ = height; + // The complete text metrics will be redone. text_metrics_.clear(); if (buffer_) @@ -1083,7 +1123,8 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) // 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_.singlepar) { + if (need_redraw + && metrics_info_.update_strategy == SingleParUpdate) { // FIXME: It should be possible to redraw only the area around // the button by doing this: // @@ -1152,8 +1193,6 @@ void BufferView::scroll(int /*lines*/) // // scrollDocView(new_top_y); // -// // Update the scrollbar. -// workArea_->setScrollbarParams(t->height(), top_y(), defaultRowHeight());} } @@ -1258,6 +1297,8 @@ bool BufferView::checkDepm(LCursor & cur, LCursor & old) if (!changed) return false; + updateLabels(*buffer_); + updateMetrics(false); buffer_->changed(); return true; @@ -1279,8 +1320,26 @@ bool BufferView::mouseSetCursor(LCursor & cur) if (!badcursor && cursor_.inTexted()) checkDepm(cur, cursor_); - cursor_ = cur; + // 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(); @@ -1338,19 +1399,25 @@ void BufferView::updateMetrics(bool singlepar) 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()) - if (tm.redoParagraph(pit)) - singlepar = false; + // Rebreak anchor paragraph. + if (!singlepar) + tm.redoParagraph(pit); // Clear out the position cache in case of full screen redraw. if (!singlepar) @@ -1358,13 +1425,12 @@ void BufferView::updateMetrics(bool singlepar) 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 -= tm.parMetrics(pit1).ascent(); --pit1; - if (!singlepar || pit1 == cursor_.bottom().pit()) + if (!singlepar) tm.redoParagraph(pit1); y1 -= tm.parMetrics(pit1).descent(); } @@ -1384,13 +1450,12 @@ 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 += tm.parMetrics(pit2).descent(); ++pit2; - if (!singlepar || pit2 == cursor_.bottom().pit()) + if (!singlepar) tm.redoParagraph(pit2); y2 += tm.parMetrics(pit2).ascent(); } @@ -1431,7 +1496,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;