]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Fix 480937a103708a651/lyxgit, second attempt.
[lyx.git] / src / BufferView.cpp
index 77750d87e3111e898f2f4ad8948e6b507f153e70..0030f33f4c1d19f11c19dfef172014f1b6fb3c52 100644 (file)
@@ -235,7 +235,9 @@ struct BufferView::Private
                mouse_position_cache_(),
                bookmark_edit_position_(-1), gui_(0),
                horiz_scroll_offset_(0)
-       {}
+       {
+               xsel_cache_.set = false;
+       }
 
        ///
        ScrollbarParameters scrollbarParameters_;
@@ -413,7 +415,7 @@ Buffer const & BufferView::buffer() const
 }
 
 
-bool BufferView::fitCursor()
+bool BufferView::needsFitCursor() const
 {
        if (cursorStatus(d->cursor_) == CUR_INSIDE) {
                frontend::FontMetrics const & fm =
@@ -444,6 +446,7 @@ void BufferView::processUpdateFlags(Update::flags flags)
        // Now do the first drawing step if needed. This consists on updating
        // the CoordCache in updateMetrics().
        // The second drawing step is done in WorkArea::redraw() if needed.
+       // FIXME: is this still true now that Buffer::changed() is used all over?
 
        // Case when no explicit update is requested.
        if (!flags) {
@@ -461,7 +464,7 @@ void BufferView::processUpdateFlags(Update::flags flags)
        if (flags == Update::FitCursor
                || flags == (Update::Decoration | Update::FitCursor)) {
                // tell the frontend to update the screen if needed.
-               if (fitCursor()) {
+               if (needsFitCursor()) {
                        showCursor();
                        return;
                }
@@ -471,7 +474,7 @@ void BufferView::processUpdateFlags(Update::flags flags)
                        return;
                }
                // no screen update is needed in principle, but this
-               // could change if cursor row needs scrolling.
+               // could change if cursor row needs horizontal scrolling.
                d->update_strategy_ = NoScreenUpdate;
                buffer_.changed(false);
                return;
@@ -493,7 +496,7 @@ void BufferView::processUpdateFlags(Update::flags flags)
        // This is done at draw() time. So we need a redraw!
        buffer_.changed(false);
 
-       if (fitCursor()) {
+       if (needsFitCursor()) {
                // The cursor is off screen so ensure it is visible.
                // refresh it:
                showCursor();
@@ -809,7 +812,7 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
                // paragraph position which is computed at draw() time.
                // So we need a redraw!
                buffer_.changed(false);
-               if (fitCursor())
+               if (needsFitCursor())
                        showCursor();
        }
 
@@ -987,7 +990,7 @@ void BufferView::updateDocumentClass(DocumentClassConstPtr olddc)
 }
 
 
-/** Return the change status at cursor position, taking in account the
+/** Return the change status at cursor position, taking into account the
  * status at each level of the document iterator (a table in a deleted
  * footnote is deleted).
  * When \param outer is true, the top slice is not looked at.
@@ -1121,16 +1124,6 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                    || getInsetByCode<InsetRef>(cur, REF_CODE));
                break;
 
-       case LFUN_CHANGES_TRACK:
-               flag.setEnabled(true);
-               flag.setOnOff(buffer_.params().track_changes);
-               break;
-
-       case LFUN_CHANGES_OUTPUT:
-               flag.setEnabled(true);
-               flag.setOnOff(buffer_.params().output_changes);
-               break;
-
        case LFUN_CHANGES_MERGE:
        case LFUN_CHANGE_NEXT:
        case LFUN_CHANGE_PREVIOUS:
@@ -1143,16 +1136,6 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                flag.setEnabled(true);
                break;
 
-       case LFUN_BUFFER_TOGGLE_COMPRESSION: {
-               flag.setOnOff(buffer_.params().compressed);
-               break;
-       }
-
-       case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: {
-               flag.setOnOff(buffer_.params().output_sync);
-               break;
-       }
-
        case LFUN_SCREEN_UP:
        case LFUN_SCREEN_DOWN:
        case LFUN_SCROLL:
@@ -1237,6 +1220,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 
        string const argument = to_utf8(cmd.argument());
        Cursor & cur = d->cursor_;
+       Cursor old = cur;
 
        // Don't dispatch function that does not apply to internal buffers.
        if (buffer_.isInternal()
@@ -1454,33 +1438,6 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                break;
        }
 
-       case LFUN_CHANGES_TRACK:
-               buffer_.params().track_changes = !buffer_.params().track_changes;
-               break;
-
-       case LFUN_CHANGES_OUTPUT:
-               buffer_.params().output_changes = !buffer_.params().output_changes;
-               if (buffer_.params().output_changes) {
-                       bool dvipost    = LaTeXFeatures::isAvailable("dvipost");
-                       bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
-                                         LaTeXFeatures::isAvailable("xcolor");
-
-                       if (!dvipost && !xcolorulem) {
-                               Alert::warning(_("Changes not shown in LaTeX output"),
-                                              _("Changes will not be highlighted in LaTeX output, "
-                                                "because neither dvipost nor xcolor/ulem are installed.\n"
-                                                "Please install these packages or redefine "
-                                                "\\lyxadded and \\lyxdeleted in the LaTeX preamble."));
-                       } else if (!xcolorulem) {
-                               Alert::warning(_("Changes not shown in LaTeX output"),
-                                              _("Changes will not be highlighted in LaTeX output "
-                                                "when using pdflatex, because xcolor and ulem are not installed.\n"
-                                                "Please install both packages or redefine "
-                                                "\\lyxadded and \\lyxdeleted in the LaTeX preamble."));
-                       }
-               }
-               break;
-
        case LFUN_CHANGE_NEXT:
                findNextChange(this);
                // FIXME: Move this LFUN to Buffer so that we don't have to do this:
@@ -1720,15 +1677,6 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
        }
                break;
 
-       case LFUN_BUFFER_TOGGLE_COMPRESSION:
-               // turn compression on/off
-               buffer_.params().compressed = !buffer_.params().compressed;
-               break;
-
-       case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC:
-               buffer_.params().output_sync = !buffer_.params().output_sync;
-               break;
-
        case LFUN_SCREEN_UP:
        case LFUN_SCREEN_DOWN: {
                Point p = getPos(cur);
@@ -1745,7 +1693,6 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        p = Point(0, 0);
                if (act == LFUN_SCREEN_DOWN && scrolled < height_)
                        p = Point(width_, height_);
-               Cursor old = cur;
                bool const in_texted = cur.inTexted();
                cur.setCursor(doc_iterator_begin(cur.buffer()));
                cur.selHandle(false);
@@ -1858,6 +1805,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        cur.pit() = cur.lastpit();
                        cur.pos() = cur.lastpos();
                }
+               cur.setCurrentFont();
                dr.screenUpdate(Update::Force);
                break;
 
@@ -2067,6 +2015,21 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 
        buffer_.undo().endUndoGroup();
        dr.dispatched(dispatched);
+
+       // NOTE: The code below is copied from Cursor::dispatch. If you
+       // need to modify this, please update the other one too.
+
+       // notify insets we just entered/left
+       if (cursor() != old) {
+               old.beginUndoGroup();
+               old.fixIfBroken();
+               bool badcursor = notifyCursorLeavesOrEnters(old, cursor());
+               if (badcursor) {
+                       cursor().fixIfBroken();
+                       resetInlineCompletionPos();
+               }
+               old.endUndoGroup();
+       }
 }
 
 
@@ -2232,6 +2195,15 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
 
        // Build temporary cursor.
        Inset * inset = d->text_metrics_[&buffer_.text()].editXY(cur, cmd.x(), cmd.y());
+       if (inset) {
+               // If inset is not editable, cur.pos() might point behind the
+               // inset (depending on cmd.x(), cmd.y()). This is needed for
+               // editing to fix bug 9628, but e.g. the context menu needs a
+               // cursor in front of the inset.
+               if (inset->hasSettings() &&
+                   cur.nextInset() != inset && cur.prevInset() == inset)
+                       cur.backwardPos();
+       }
 
        // Put anchor at the same position.
        cur.resetAnchor();
@@ -2339,13 +2311,19 @@ int BufferView::scrollUp(int offset)
 
 
 void BufferView::setCursorFromRow(int row)
+{
+       setCursorFromRow(row, buffer_.texrow());
+}
+
+
+void BufferView::setCursorFromRow(int row, TexRow const & texrow)
 {
        int tmpid;
        int tmppos;
        pit_type newpit = 0;
        pos_type newpos = 0;
 
-       buffer_.texrow().getIdFromRow(row, tmpid, tmppos);
+       texrow.getIdFromRow(row, tmpid, tmppos);
 
        bool posvalid = (tmpid != -1);
        if (posvalid) {
@@ -2415,9 +2393,9 @@ void BufferView::gotoLabel(docstring const & label)
                Buffer const * buf = *it;
 
                // find label
-               Toc & toc = buf->tocBackend().toc("label");
-               TocIterator toc_it = toc.begin();
-               TocIterator end = toc.end();
+               shared_ptr<Toc> toc = buf->tocBackend().toc("label");
+               TocIterator toc_it = toc->begin();
+               TocIterator end = toc->end();
                for (; toc_it != end; ++toc_it) {
                        if (label == toc_it->str()) {
                                lyx::dispatch(toc_it->action());
@@ -2468,6 +2446,7 @@ void BufferView::setCursor(DocIterator const & dit)
 
        d->cursor_.setCursor(dit);
        d->cursor_.setSelection(false);
+       d->cursor_.setCurrentFont();
        // FIXME
        // It seems on general grounds as if this is probably needed, but
        // it is not yet clear.
@@ -2495,7 +2474,7 @@ bool BufferView::checkDepm(Cursor & cur, Cursor & old)
        d->cursor_ = cur;
 
        // we would rather not do this here, but it needs to be done before
-       // the changed() signal is sent.
+       // the changed() signal is sent.
        buffer_.updateBuffer();
 
        buffer_.changed(true);
@@ -2784,7 +2763,7 @@ Point BufferView::coordOffset(DocIterator const & dit) const
        int lastw = 0;
 
        // Addup contribution of nested insets, from inside to outside,
-       // keeping the outer paragraph for a special handling below
+       // keeping the outer paragraph for a special handling below
        for (size_t i = dit.depth() - 1; i >= 1; --i) {
                CursorSlice const & sl = dit[i];
                int xx = 0;
@@ -2814,8 +2793,7 @@ Point BufferView::coordOffset(DocIterator const & dit) const
                        // FIXME (Abdel 23/09/2007): this is a bit messy because of the
                        // elimination of Inset::dim_ cache. This coordOffset() method needs
                        // to be rewritten in light of the new design.
-                       Dimension const & dim = parMetrics(dit[i - 1].text(),
-                               dit[i - 1].pit()).insetDimension(&sl.inset());
+                       Dimension const & dim = coordCache().getInsets().dim(&sl.inset());
                        lastw = dim.wid;
                } else {
                        Dimension const dim = sl.inset().dimension(*this);
@@ -2965,52 +2943,71 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi)
                return;
        ParagraphMetrics const & pm = tm.parMetrics(rowSlice.pit());
        Row const & row = pm.getRow(rowSlice.pos(),
-                                   d->cursor_.boundary()
-                                   && rowSlice == d->cursor_.top());
+                                   d->cursor_.boundary() && rowSlice == d->cursor_.top());
        rowSlice.pos() = row.pos();
 
        // Set the row on which the cursor lives.
        setCurrentRowSlice(rowSlice);
 
-       /** FIXME: the code below adds an extraneous computation of inset
-        * positions, and can therefore be bad for performance (think for
-        * example about a very large tabular inset. Redawing the row
-        * where it is means redrawing the whole screen).
-        *
-        * The bug that this fixes is the following: assume that there is
-        * a very large math inset. Upon entering the inset, when pressing
-        * `End', the row is not scrolled and the cursor is not visible. I
-        * am not sure why the extra row computation fixes the problem,
-        * actually.
-        *
-        * A proper fix should be found and this code should be removed.
-        */
-       // Force the recomputation of inset positions
-       bool const drawing = pi.pain.isDrawingEnabled();
-       pi.pain.setDrawingEnabled(false);
-       // No need to care about vertical position.
-       RowPainter rp(pi, buffer().text(), d->cursor_.bottom().pit(), row,
-                     -d->horiz_scroll_offset_, 0);
-       rp.paintText();
-       pi.pain.setDrawingEnabled(drawing);
-       /** END of bad code */
-
        // Current x position of the cursor in pixels
-       int const cur_x = getPos(d->cursor_).x_;
+       int cur_x = getPos(d->cursor_).x_;
+
+       // If cursor offset is left margin and offset is not the leftmost
+       // position of the row, there is a cache problem.
+       if (cur_x == row.left_margin && !row.empty()
+           && d->cursor_.pos() != row.front().left_pos()) {
+               /** FIXME: the code below adds an extraneous computation of
+                * inset positions, and can therefore be bad for performance
+                * (think for example about a very large tabular inset.
+                * Redawing the row where it is means redrawing the whole
+                * screen).
+                *
+                * The bug that this fixes is the following: assume that there
+                * is a very large math inset. Upon entering the inset, when
+                * pressing `End', the row is not scrolled and the cursor is
+                * not visible. The extra row computation makes sure that the
+                * inset positions are correctly computed and set in the
+                * cache. This would not happen if we did not have two-stage
+                * drawing.
+                *
+                * A proper fix should be found and this code should be removed.
+                */
+               // Force the recomputation of inset positions
+               bool const drawing = pi.pain.isDrawingEnabled();
+               pi.pain.setDrawingEnabled(false);
+               // No need to care about vertical position.
+               RowPainter rp(pi, buffer().text(), d->cursor_.bottom().pit(), row,
+                             -d->horiz_scroll_offset_, 0);
+               rp.paintText();
+               pi.pain.setDrawingEnabled(drawing);
+
+               // Recompute current Current x position of the cursor in pixels
+               cur_x = getPos(d->cursor_).x_;
+       }
 
        // Horizontal scroll offset of the cursor row in pixels
        int offset = d->horiz_scroll_offset_;
-       int const MARGIN = Length(2, Length::EM).inPixels(workWidth());
-       if (cur_x < offset + MARGIN) {
-               // scroll right
-               offset = cur_x - MARGIN;
-       } else if (cur_x > offset + workWidth() - MARGIN) {
-               // scroll left
-               offset = cur_x - workWidth() + MARGIN;
+       int const MARGIN = 2 * theFontMetrics(d->cursor_.real_current_font).em()
+                          + row.right_margin;
+       if (row.right_x() <= workWidth() - row.right_margin) {
+               // Row is narrower than the work area, no offset needed.
+               offset = 0;
+       } else {
+               if (cur_x - offset < MARGIN) {
+                       // cursor would be too far right
+                       offset = cur_x - MARGIN;
+               } else if (cur_x - offset > workWidth() - MARGIN) {
+                       // cursor would be too far left
+                       offset = cur_x - workWidth() + MARGIN;
+               }
+               // Correct the offset to make sure that we do not scroll too much
+               if (offset < 0)
+                       offset = 0;
+               if (row.right_x() - offset < workWidth() - row.right_margin)
+                       offset = row.right_x() - workWidth() + row.right_margin;
        }
 
-       if (offset < row.left_margin || row.width() <= workWidth())
-               offset = 0;
+       //lyxerr << "cur_x=" << cur_x << ", offset=" << offset << ", row.wid=" << row.width() << ", margin=" << MARGIN << endl;
 
        if (offset != d->horiz_scroll_offset_)
                LYXERR(Debug::PAINTING, "Horiz. scroll offset changed from "
@@ -3051,7 +3048,7 @@ void BufferView::draw(frontend::Painter & pain)
                LYXERR(Debug::PAINTING, "Strategy: NoScreenUpdate");
                pi.full_repaint = true;
                pi.pain.setDrawingEnabled(false);
-               tm.draw(pi, 0, y);
+               tm.draw(pi, 0, y);
                break;
 
        case SingleParUpdate:
@@ -3060,7 +3057,7 @@ void BufferView::draw(frontend::Painter & pain)
                // In general, only the current row of the outermost paragraph
                // will be redrawn. Particular cases where selection spans
                // multiple paragraph are correctly detected in TextMetrics.
-               tm.draw(pi, 0, y);
+               tm.draw(pi, 0, y);
                break;
 
        case DecorationUpdate: