]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Correct comment
[lyx.git] / src / BufferView.cpp
index 40d8643363763547574d93a1c887a4cdbf765fe5..e75bc5e0b93f0a82b69df51b1ceb5b27ae5e2560 100644 (file)
@@ -35,7 +35,6 @@
 #include "Language.h"
 #include "LaTeXFeatures.h"
 #include "LayoutFile.h"
-#include "Length.h"
 #include "Lexer.h"
 #include "LyX.h"
 #include "LyXAction.h"
@@ -81,6 +80,7 @@
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lassert.h"
+#include "support/Length.h"
 #include "support/lstrings.h"
 #include "support/lyxlib.h"
 #include "support/Package.h"
@@ -110,7 +110,7 @@ T * getInsetByCode(Cursor const & cur, InsetCode code)
        Inset * inset = it.nextInset();
        if (inset && inset->lyxCode() == code)
                return static_cast<T*>(inset);
-       return 0;
+       return nullptr;
 }
 
 
@@ -179,13 +179,6 @@ bool findInset(DocIterator & dit, vector<InsetCode> const & codes,
 }
 
 
-/// Looks for next inset with the given code
-void findInset(DocIterator & dit, InsetCode code, bool same_content)
-{
-       findInset(dit, vector<InsetCode>(1, code), same_content);
-}
-
-
 /// Moves cursor to the next inset with one of the given codes.
 void gotoInset(BufferView * bv, vector<InsetCode> const & codes,
               bool same_content)
@@ -202,13 +195,6 @@ void gotoInset(BufferView * bv, vector<InsetCode> const & codes,
 }
 
 
-/// Moves cursor to the next inset with given code.
-void gotoInset(BufferView * bv, InsetCode code, bool same_content)
-{
-       gotoInset(bv, vector<InsetCode>(1, code), same_content);
-}
-
-
 /// A map from a Text to the associated text metrics
 typedef map<Text const *, TextMetrics> TextMetricsCache;
 
@@ -233,13 +219,11 @@ struct BufferView::Private
        Private(BufferView & bv) :
                update_strategy_(FullScreenUpdate),
                update_flags_(Update::Force),
-               wh_(0), cursor_(bv),
-               anchor_pit_(0), anchor_ypos_(0),
-               inlineCompletionUniqueChars_(0),
-               last_inset_(0), clickable_inset_(false),
-               mouse_position_cache_(),
-               bookmark_edit_position_(-1), gui_(0),
-               horiz_scroll_offset_(0)
+               cursor_(bv), anchor_pit_(0), anchor_ypos_(0),
+               wh_(0), inlineCompletionUniqueChars_(0),
+               last_inset_(nullptr), mouse_position_cache_(),
+               gui_(nullptr), bookmark_edit_position_(-1),
+               horiz_scroll_offset_(0), clickable_inset_(false)
        {
                xsel_cache_.set = false;
        }
@@ -256,8 +240,6 @@ struct BufferView::Private
        typedef map<MathData const *, MathRow> MathRows;
        MathRows math_rows_;
 
-       /// Estimated average par height for scrollbar.
-       int wh_;
        /// this is used to handle XSelection events in the right manner.
        struct {
                CursorSlice cursor;
@@ -270,6 +252,8 @@ struct BufferView::Private
        pit_type anchor_pit_;
        ///
        int anchor_ypos_;
+       /// Estimated average par height for scrollbar.
+       int wh_;
        ///
        vector<int> par_height_;
 
@@ -288,17 +272,12 @@ struct BufferView::Private
          * Not owned, so don't delete.
          */
        Inset const * last_inset_;
-       /// are we hovering something that we can click
-       bool clickable_inset_;
 
        /// position of the mouse at the time of the last mouse move
        /// This is used to update the hovering status of inset in
        /// cases where the buffer is scrolled, but the mouse didn't move.
        Point mouse_position_cache_;
 
-       // cache for id of the paragraph which was edited the last time
-       int bookmark_edit_position_;
-
        mutable TextMetricsCache text_metrics_;
 
        /// Whom to notify.
@@ -314,10 +293,15 @@ struct BufferView::Private
 
        /// When the row where the cursor lies is scrolled, this
        /// contains the scroll offset
+       // cache for id of the paragraph which was edited the last time
+       int bookmark_edit_position_;
+
        int horiz_scroll_offset_;
        /// a slice pointing to the start of the row where the cursor
        /// is (at last draw time)
        CursorSlice current_row_slice_;
+       /// are we hovering something that we can click
+       bool clickable_inset_;
 };
 
 
@@ -345,9 +329,10 @@ BufferView::~BufferView()
        // That is to say, if a cursor is in a nested inset, it will be
        // restore to the left of the top level inset.
        LastFilePosSection::FilePos fp;
+       fp.file = buffer_.fileName();
        fp.pit = d->cursor_.bottom().pit();
        fp.pos = d->cursor_.bottom().pos();
-       theSession().lastFilePos().save(buffer_.fileName(), fp);
+       theSession().lastFilePos().save(fp);
 
        if (d->last_inset_)
                d->last_inset_->setMouseHover(this, false);
@@ -375,6 +360,20 @@ int BufferView::leftMargin() const
 }
 
 
+int BufferView::topMargin() const
+{
+       // original value was 20px, which is 0.2in at 100dpi
+       return zoomedPixels(20);
+}
+
+
+int BufferView::bottomMargin() const
+{
+       // original value was 20px, which is 0.2in at 100dpi
+       return zoomedPixels(20);
+}
+
+
 int BufferView::inPixels(Length const & len) const
 {
        Font const font = buffer().params().getFont();
@@ -526,9 +525,18 @@ void BufferView::processUpdateFlags(Update::flags flags)
        // Then make sure that the screen contains the cursor if needed
        if (flags & Update::FitCursor) {
                if (needsFitCursor()) {
-                       scrollToCursor(d->cursor_, false);
+                       // First try to make the selection start visible
+                       // (which is just the cursor when there is no selection)
+                       scrollToCursor(d->cursor_.selectionBegin(), false);
                        // Metrics have to be recomputed (maybe again)
-                       updateMetrics(flags);
+                       updateMetrics();
+                       // Is the cursor visible? (only useful if cursor is at end of selection)
+                       if (needsFitCursor()) {
+                               // then try to make cursor visible instead
+                               scrollToCursor(d->cursor_, false);
+                               // Metrics have to be recomputed (maybe again)
+                               updateMetrics(flags);
+                       }
                }
                flags = flags & ~Update::FitCursor;
        }
@@ -930,13 +938,16 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter)
        if (height_ == 0)
                return false;
 
-       LYXERR(Debug::SCROLLING, "recentering!");
+       if (recenter)
+         LYXERR(Debug::SCROLLING, "recentering and scrolling to cursor");
+       else
+         LYXERR(Debug::SCROLLING, "scrolling to cursor");
 
        CursorSlice const & bot = dit.bottom();
        TextMetrics & tm = d->text_metrics_[bot.text()];
 
        pos_type const max_pit = pos_type(bot.text()->paragraphs().size() - 1);
-       int bot_pit = bot.pit();
+       pos_type bot_pit = bot.pit();
        if (bot_pit > max_pit) {
                // FIXME: Why does this happen?
                LYXERR0("bottom pit is greater that max pit: "
@@ -1259,7 +1270,7 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 Inset * BufferView::editedInset(string const & name) const
 {
        map<string, Inset *>::const_iterator it = d->edited_insets_.find(name);
-       return it == d->edited_insets_.end() ? 0 : it->second;
+       return it == d->edited_insets_.end() ? nullptr : it->second;
 }
 
 
@@ -1519,25 +1530,36 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
        }
 
        case LFUN_NOTE_NEXT:
-               gotoInset(this, NOTE_CODE, false);
+               gotoInset(this, { NOTE_CODE }, false);
+               // FIXME: if SinglePar is changed to act on the inner
+               // paragraph, this will not be OK anymore. The update is
+               // useful for auto-open collapsible insets.
+               dr.screenUpdate(Update::SinglePar | Update::FitCursor);
                break;
 
        case LFUN_REFERENCE_NEXT: {
-               vector<InsetCode> tmp;
-               tmp.push_back(LABEL_CODE);
-               tmp.push_back(REF_CODE);
-               gotoInset(this, tmp, true);
+               gotoInset(this, { LABEL_CODE, REF_CODE }, true);
+               // FIXME: if SinglePar is changed to act on the inner
+               // paragraph, this will not be OK anymore. The update is
+               // useful for auto-open collapsible insets.
+               dr.screenUpdate(Update::SinglePar | Update::FitCursor);
                break;
        }
 
        case LFUN_CHANGE_NEXT:
                findNextChange(this);
+               if (cur.inset().isTable())
+                       // In tables, there might be whole changed rows or columns
+                       cur.dispatch(cmd);
                // FIXME: Move this LFUN to Buffer so that we don't have to do this:
                dr.screenUpdate(Update::Force | Update::FitCursor);
                break;
 
        case LFUN_CHANGE_PREVIOUS:
                findPreviousChange(this);
+               if (cur.inset().isTable())
+                       // In tables, there might be whole changed rows or columns
+                       cur.dispatch(cmd);
                // FIXME: Move this LFUN to Buffer so that we don't have to do this:
                dr.screenUpdate(Update::Force | Update::FitCursor);
                break;
@@ -1550,32 +1572,43 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                }
                break;
 
-       case LFUN_ALL_CHANGES_ACCEPT:
+       case LFUN_ALL_CHANGES_ACCEPT: {
                // select complete document
                cur.reset();
                cur.selHandle(true);
                buffer_.text().cursorBottom(cur);
                // accept everything in a single step to support atomic undo
+               // temporarily disable track changes in order to end with really
+               // no new (e.g., DPSM-caused) changes (see #7487)
+               bool const track = buffer_.params().track_changes;
+               buffer_.params().track_changes = false;
                buffer_.text().acceptOrRejectChanges(cur, Text::ACCEPT);
+               buffer_.params().track_changes = track;
                cur.resetAnchor();
                // FIXME: Move this LFUN to Buffer so that we don't have to do this:
                dr.screenUpdate(Update::Force | Update::FitCursor);
                dr.forceBufferUpdate();
                break;
+       }
 
-       case LFUN_ALL_CHANGES_REJECT:
+       case LFUN_ALL_CHANGES_REJECT: {
                // select complete document
                cur.reset();
                cur.selHandle(true);
                buffer_.text().cursorBottom(cur);
                // reject everything in a single step to support atomic undo
-               // Note: reject does not work recursively; the user may have to repeat the operation
+               // temporarily disable track changes in order to end with really
+               // no new (e.g., DPSM-caused) changes (see #7487)
+               bool const track = buffer_.params().track_changes;
+               buffer_.params().track_changes = false;
                buffer_.text().acceptOrRejectChanges(cur, Text::REJECT);
+               buffer_.params().track_changes = track;
                cur.resetAnchor();
                // FIXME: Move this LFUN to Buffer so that we don't have to do this:
                dr.screenUpdate(Update::Force | Update::FitCursor);
                dr.forceBufferUpdate();
                break;
+       }
 
        case LFUN_WORD_FIND_FORWARD:
        case LFUN_WORD_FIND_BACKWARD: {
@@ -1687,7 +1720,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 
        case LFUN_BIBTEX_DATABASE_ADD: {
                Cursor tmpcur = cur;
-               findInset(tmpcur, BIBTEX_CODE, false);
+               findInset(tmpcur, { BIBTEX_CODE }, false);
                InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur,
                                                BIBTEX_CODE);
                if (inset) {
@@ -1699,7 +1732,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 
        case LFUN_BIBTEX_DATABASE_DEL: {
                Cursor tmpcur = cur;
-               findInset(tmpcur, BIBTEX_CODE, false);
+               findInset(tmpcur, { BIBTEX_CODE }, false);
                InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur,
                                                BIBTEX_CODE);
                if (inset) {
@@ -2182,7 +2215,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 }
 
 
-docstring const BufferView::requestSelection()
+docstring BufferView::requestSelection()
 {
        Cursor & cur = d->cursor_;
 
@@ -2239,7 +2272,7 @@ Inset const * BufferView::getCoveringInset(Text const & text,
        TextMetrics & tm = d->text_metrics_[&text];
        Inset * inset = tm.checkInsetHit(x, y);
        if (!inset)
-               return 0;
+               return nullptr;
 
        if (!inset->descendable(*this))
                // No need to go further down if the inset is not
@@ -2280,7 +2313,7 @@ void BufferView::updateHoveredInset() const
        if (d->last_inset_) {
                // Remove the hint on the last hovered inset (if any).
                need_redraw |= d->last_inset_->setMouseHover(this, false);
-               d->last_inset_ = 0;
+               d->last_inset_ = nullptr;
        }
 
        if (covering_inset && covering_inset->setMouseHover(this, true)) {
@@ -2311,7 +2344,7 @@ void BufferView::clearLastInset(Inset * inset) const
                LYXERR0("Wrong last_inset!");
                LATTEST(false);
        }
-       d->last_inset_ = 0;
+       d->last_inset_ = nullptr;
 }
 
 
@@ -2739,23 +2772,12 @@ Cursor const & BufferView::cursor() const
 }
 
 
-void BufferView::setCursorLanguage(std::string const & code)
-{
-       Language const * lang = languages.getFromCode(code, buffer_.getLanguages());
-       if (lang) {
-               d->cursor_.current_font.setLanguage(lang);
-               d->cursor_.real_current_font.setLanguage(lang);
-       } else
-               LYXERR0("setCursorLanguage: unknown language code " << code);
-}
-
-
 bool BufferView::singleParUpdate()
 {
        Text & buftext = buffer_.text();
        pit_type const bottom_pit = d->cursor_.bottom().pit();
        TextMetrics & tm = textMetrics(&buftext);
-       int old_height = tm.parMetrics(bottom_pit).height();
+       Dimension const old_dim = tm.parMetrics(bottom_pit).dim();
 
        // make sure inline completion pointer is ok
        if (d->inlineCompletionPos_.fixIfBroken())
@@ -2766,11 +2788,16 @@ bool BufferView::singleParUpdate()
        // (if this paragraph contains insets etc., rebreaking will
        // recursively descend)
        tm.redoParagraph(bottom_pit);
-       ParagraphMetrics const & pm = tm.parMetrics(bottom_pit);
-       if (pm.height() != old_height)
+       ParagraphMetrics & pm = tm.parMetrics(bottom_pit);
+       if (pm.height() != old_dim.height()) {
                // Paragraph height has changed so we cannot proceed to
                // the singlePar optimisation.
                return false;
+       }
+       // Since position() points to the baseline of the first row, we
+       // may have to update it. See ticket #11601 for an example where
+       // the height does not change but the ascent does.
+       pm.setPosition(pm.position() - old_dim.ascent() + pm.ascent());
 
        tm.updatePosCache(bottom_pit);
 
@@ -2818,7 +2845,7 @@ void BufferView::updateMetrics(Update::flags & update_flags)
 
        // Rebreak anchor paragraph.
        tm.redoParagraph(d->anchor_pit_);
-       ParagraphMetrics & anchor_pm = tm.par_metrics_[d->anchor_pit_];
+       ParagraphMetrics & anchor_pm = tm.parMetrics(d->anchor_pit_);
 
        // position anchor
        if (d->anchor_pit_ == 0) {
@@ -2845,7 +2872,7 @@ void BufferView::updateMetrics(Update::flags & update_flags)
        pit_type pit1 = d->anchor_pit_ - 1;
        for (; pit1 >= 0 && y1 >= 0; --pit1) {
                tm.redoParagraph(pit1);
-               ParagraphMetrics & pm = tm.par_metrics_[pit1];
+               ParagraphMetrics & pm = tm.parMetrics(pit1);
                y1 -= pm.descent();
                // Save the paragraph position in the cache.
                pm.setPosition(y1);
@@ -2859,7 +2886,7 @@ void BufferView::updateMetrics(Update::flags & update_flags)
        pit_type pit2 = d->anchor_pit_ + 1;
        for (; pit2 < npit && y2 <= height_; ++pit2) {
                tm.redoParagraph(pit2);
-               ParagraphMetrics & pm = tm.par_metrics_[pit2];
+               ParagraphMetrics & pm = tm.parMetrics(pit2);
                y2 += pm.ascent();
                // Save the paragraph position in the cache.
                pm.setPosition(y2);
@@ -3195,7 +3222,6 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
                // however, the different coordinates of insets and paragraphs
                // needs to be updated.
                LYXERR(Debug::PAINTING, "Strategy: NoScreenUpdate");
-               pi.full_repaint = false;
                if (pain.isNull()) {
                        pi.full_repaint = true;
                        tm.draw(pi, 0, y);
@@ -3251,6 +3277,7 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
                                : "\t\t *** END DRAWING ***"));
 
        // The scrollbar needs an update.
+       // FIXME: does it always? see ticket #11947.
        updateScrollbar();
 
        // Normalize anchor for next time