]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Check path of Qt tools if qtchooser is detected
[lyx.git] / src / BufferView.cpp
index 9a9a77b4e99861d9e69e89df5fdbd956f95aa00e..f02cb6668613fba7a97ca28763d0cbf8dfc5a472 100644 (file)
@@ -351,11 +351,12 @@ BufferView::~BufferView()
 
 int BufferView::rightMargin() const
 {
+       // The value used to be hardcoded to 10, which is 2.5mm at 100dpi
+       int const default_margin = Length(2.5, Length::MM).inPixels(0);
        // The additional test for the case the outliner is opened.
-       if (!full_screen_ ||
-               !lyxrc.full_screen_limit ||
-               width_ < lyxrc.full_screen_width + 20)
-                       return 10;
+       if (!full_screen_ || !lyxrc.full_screen_limit
+           || width_ < lyxrc.full_screen_width + 2 * default_margin)
+               return default_margin;
 
        return (width_ - lyxrc.full_screen_width) / 2;
 }
@@ -369,13 +370,13 @@ int BufferView::leftMargin() const
 
 bool BufferView::isTopScreen() const
 {
-       return d->scrollbarParameters_.position == d->scrollbarParameters_.min;
+       return 0 == d->scrollbarParameters_.min;
 }
 
 
 bool BufferView::isBottomScreen() const
 {
-       return d->scrollbarParameters_.position == d->scrollbarParameters_.max;
+       return 0 == d->scrollbarParameters_.max;
 }
 
 
@@ -433,7 +434,7 @@ bool BufferView::needsFitCursor() const
 void BufferView::processUpdateFlags(Update::flags flags)
 {
        // This is close to a hot-path.
-       LYXERR(Debug::DEBUG, "BufferView::processUpdateFlags()"
+       LYXERR(Debug::PAINTING, "BufferView::processUpdateFlags()"
                << "[fitcursor = " << (flags & Update::FitCursor)
                << ", forceupdate = " << (flags & Update::Force)
                << ", singlepar = " << (flags & Update::SinglePar)
@@ -558,7 +559,6 @@ void BufferView::updateScrollbar()
        for (size_t i = last.first + 1; i != parsize; ++i)
                d->scrollbarParameters_.max += d->par_height_[i];
 
-       d->scrollbarParameters_.position = 0;
        // The reference is the top position so we remove one page.
        if (lyxrc.scroll_below_document)
                d->scrollbarParameters_.max -= minVisiblePart();
@@ -599,17 +599,19 @@ string BufferView::contextMenu(int x, int y) const
 }
 
 
-void BufferView::scrollDocView(int value, bool update)
+
+void BufferView::scrollDocView(int const value, bool update)
 {
-       int const offset = value - d->scrollbarParameters_.position;
+       // The scrollbar values are relative to the top of the screen, therefore the
+       // offset is equal to the target value.
 
        // No scrolling at all? No need to redraw anything
-       if (offset == 0)
+       if (value == 0)
                return;
 
        // If the offset is less than 2 screen height, prefer to scroll instead.
-       if (abs(offset) <= 2 * height_) {
-               d->anchor_ypos_ -= offset;
+       if (abs(value) <= 2 * height_) {
+               d->anchor_ypos_ -= value;
                buffer_.changed(true);
                updateHoveredInset();
                return;
@@ -706,9 +708,7 @@ Change const BufferView::getCurrentChange() const
 
        DocIterator dit = d->cursor_.selectionBegin();
        // The selected content might have been changed (see #7685)
-       while (dit.inMathed())
-               // Find enclosing text cursor
-               dit.pop_back();
+       dit = dit.getInnerText();
        return dit.paragraph().lookupChange(dit.pos());
 }
 
@@ -808,6 +808,8 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
                setCursor(dit);
                // set the current font.
                d->cursor_.setCurrentFont();
+               // Do not forget to reset the anchor (see #9912)
+               d->cursor_.resetAnchor();
                // To center the screen on this new position we need the
                // paragraph position which is computed at draw() time.
                // So we need a redraw!
@@ -1124,38 +1126,14 @@ 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:
        case LFUN_ALL_CHANGES_ACCEPT:
        case LFUN_ALL_CHANGES_REJECT:
-               // TODO: context-sensitive enabling of LFUNs
-               // In principle, these command should only be enabled if there
-               // is a change in the document. However, without proper
-               // optimizations, this will inevitably result in poor performance.
-               flag.setEnabled(true);
+               flag.setEnabled(buffer_.areChangesPresent());
                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:
@@ -1371,6 +1349,16 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                else
                        dr.screenUpdate(Update::Force | Update::FitCursor);
                dr.forceBufferUpdate();
+               // we only need to do this if we have deleted or restored a
+               // BiBTeX inset. but there is no other place to do it. one
+               // obvious idea is to try to do it in a copy constructor for
+               // InsetBibTeX, but when that is invoked, the buffer_ member 
+               // is not yet set. another idea is to look at the InsetLists
+               // of the various paragraphs. but we'd have to recurse through
+               // the contained insets to make that work. it doesn't seem to
+               // be worth it, as this will not happen that often.
+               buffer().invalidateBibfileCache();
+               buffer().removeBiblioTempFiles();
                break;
 
        case LFUN_REDO:
@@ -1381,6 +1369,9 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                else
                        dr.screenUpdate(Update::Force | Update::FitCursor);
                dr.forceBufferUpdate();
+               // see above
+               buffer().invalidateBibfileCache();
+               buffer().removeBiblioTempFiles();
                break;
 
        case LFUN_FONT_STATE:
@@ -1458,33 +1449,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:
@@ -1637,7 +1601,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                break;
 
        case LFUN_MARK_TOGGLE:
-               cur.setSelection(false);
+               cur.selection(false);
                if (cur.mark()) {
                        cur.setMark(false);
                        dr.setMessage(from_utf8(N_("Mark removed")));
@@ -1724,15 +1688,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);
@@ -1830,26 +1785,30 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
        }
 
 
-       case LFUN_INSET_SELECT_ALL:
-               if (cur.depth() > 1
+       case LFUN_INSET_SELECT_ALL: {
+               // true if all cells are selected
+               bool const all_selected = cur.depth() > 1
                    && cur.selBegin().at_begin()
-                   && cur.selEnd().at_end()) {
-                       // All the contents of the inset if selected.
+                   && cur.selEnd().at_end();
+               // true if some cells are selected
+               bool const cells_selected = cur.depth() > 1
+                   && cur.selBegin().at_cell_begin()
+                       && cur.selEnd().at_cell_end();
+               if (all_selected || (cells_selected && !cur.inset().isTable())) {
+                       // All the contents of the inset if selected, or only at
+                       // least one cell but inset is not a table.
                        // Select the inset from outside.
                        cur.pop();
                        cur.resetAnchor();
-                       cur.setSelection(true);
+                       cur.selection(true);
                        cur.posForward();
-               } else if (cur.selBegin().idx() != cur.selEnd().idx()
-                          || (cur.depth() > 1
-                                  && cur.selBegin().at_cell_begin()
-                              && cur.selEnd().at_cell_end())) {
-                       // At least one complete cell is selected.
+               } else if (cells_selected) {
+                       // At least one complete cell is selected and inset is a table.
                        // Select all cells
                        cur.idx() = 0;
                        cur.pos() = 0;
                        cur.resetAnchor();
-                       cur.setSelection(true);
+                       cur.selection(true);
                        cur.idx() = cur.lastidx();
                        cur.pos() = cur.lastpos();
                } else {
@@ -1857,13 +1816,14 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        cur.pit() = 0;
                        cur.pos() = 0;
                        cur.resetAnchor();
-                       cur.setSelection(true);
+                       cur.selection(true);
                        cur.pit() = cur.lastpit();
                        cur.pos() = cur.lastpos();
                }
                cur.setCurrentFont();
                dr.screenUpdate(Update::Force);
                break;
+       }
 
 
        // This would be in Buffer class if only Cursor did not
@@ -1903,9 +1863,17 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        if (!cur.nextInset() || cur.nextInset() == ins)
                                cur.forwardInset();
                }
-               cur.endUndoGroup();
                cur = savecur;
                cur.fixIfBroken();
+               /** This is a dummy undo record only to remember the cursor
+                * that has just been set; this will be used on a redo action
+                * (see ticket #10097)
+
+                * FIXME: a better fix would be to have a way to set the
+                * cursor value directly, but I am not sure it is worth it.
+                */
+               cur.recordUndo();
+               cur.endUndoGroup();
                dr.screenUpdate(Update::Force);
                dr.forceBufferUpdate();
 
@@ -2177,7 +2145,7 @@ void BufferView::updateHoveredInset() const
        int const y = d->mouse_position_cache_.y_;
        Inset const * covering_inset = getCoveringInset(buffer_.text(), x, y);
 
-       d->clickable_inset_ = covering_inset && covering_inset->clickable(x, y);
+       d->clickable_inset_ = covering_inset && covering_inset->clickable(*this, x, y);
 
        if (covering_inset == d->last_inset_)
                // Same inset, no need to do anything...
@@ -2233,7 +2201,7 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
        Cursor old = cursor();
        Cursor cur(*this);
        cur.push(buffer_.inset());
-       cur.setSelection(d->cursor_.selection());
+       cur.selection(d->cursor_.selection());
 
        // Either the inset under the cursor or the
        // surrounding Text will handle this event.
@@ -2256,9 +2224,14 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
                // 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() &&
+               if ((inset->hasSettings() || !inset->contextMenuName().empty()
+                    || inset->lyxCode() == SEPARATOR_CODE) &&
                    cur.nextInset() != inset && cur.prevInset() == inset)
-                       cur.backwardPos();
+                       cur.posBackward();
+       } else if (cur.inTexted() && cur.pos()
+                       && cur.paragraph().isEnvSeparator(cur.pos() - 1)) {
+               // Always place cursor in front of a separator inset.
+               cur.posBackward();
        }
 
        // Put anchor at the same position.
@@ -2278,8 +2251,6 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
        if (!inset || !cur.result().dispatched())
                cur.dispatch(cmd);
 
-       cur.endUndoGroup();
-
        // Notify left insets
        if (cur != old) {
                bool badcursor = old.fixIfBroken() | cur.fixIfBroken();
@@ -2288,6 +2259,8 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
                        cursor().fixIfBroken();
        }
 
+       cur.endUndoGroup();
+
        // Do we have a selection?
        theSelection().haveSelection(cursor().selection());
 
@@ -2415,7 +2388,7 @@ void BufferView::setCursorFromRow(int row, TexRow const & texrow)
        }
        d->cursor_.reset();
        buffer_.text().setCursor(d->cursor_, newpit, newpos);
-       d->cursor_.setSelection(false);
+       d->cursor_.selection(false);
        d->cursor_.resetAnchor();
        recenter();
 }
@@ -2450,8 +2423,8 @@ void BufferView::gotoLabel(docstring const & label)
 
                // find label
                shared_ptr<Toc> toc = buf->tocBackend().toc("label");
-               TocIterator toc_it = toc->begin();
-               TocIterator end = toc->end();
+               Toc::const_iterator toc_it = toc->begin();
+               Toc::const_iterator end = toc->end();
                for (; toc_it != end; ++toc_it) {
                        if (label == toc_it->str()) {
                                lyx::dispatch(toc_it->action());
@@ -2501,7 +2474,7 @@ void BufferView::setCursor(DocIterator const & dit)
                dit[i].inset().edit(d->cursor_, true);
 
        d->cursor_.setCursor(dit);
-       d->cursor_.setSelection(false);
+       d->cursor_.selection(false);
        d->cursor_.setCurrentFont();
        // FIXME
        // It seems on general grounds as if this is probably needed, but
@@ -2630,7 +2603,7 @@ bool BufferView::selectIfEmpty(DocIterator & cur)
        d->cursor_.setCursor(cur);
        d->cursor_.pit() = beg_pit;
        d->cursor_.pos() = 0;
-       d->cursor_.setSelection(false);
+       d->cursor_.selection(false);
        d->cursor_.resetAnchor();
        d->cursor_.pit() = end_pit;
        d->cursor_.pos() = end_pos;
@@ -2955,15 +2928,26 @@ int BufferView::horizScrollOffset() const
 }
 
 
-CursorSlice const & BufferView::currentRowSlice() const
+int BufferView::horizScrollOffset(Text const * text,
+                                  pit_type pit, pos_type pos) const
 {
-       return d->current_row_slice_;
+       // Is this a row that is currently scrolled?
+       if (!d->current_row_slice_.empty()
+           && &text->inset() == d->current_row_slice_.inset().asInsetText()
+           && pit ==  d->current_row_slice_.pit()
+           && pos ==  d->current_row_slice_.pos())
+               return d->horiz_scroll_offset_;
+       return 0;
 }
 
 
-CursorSlice const & BufferView::lastRowSlice() const
+bool BufferView::hadHorizScrollOffset(Text const * text,
+                                      pit_type pit, pos_type pos) const
 {
-       return d->last_row_slice_;
+       return !d->last_row_slice_.empty()
+              && &text->inset() == d->last_row_slice_.inset().asInsetText()
+              && pit ==  d->last_row_slice_.pit()
+              && pos ==  d->last_row_slice_.pos();
 }
 
 
@@ -3005,13 +2989,9 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi)
        // Set the row on which the cursor lives.
        setCurrentRowSlice(rowSlice);
 
-       // Current x position of the cursor in pixels
-       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()) {
+       // If insets referred to by cursor are not all in the cache, the positions
+       // need to be recomputed.
+       if (!d->cursor_.inCoordCache()) {
                /** 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.
@@ -3026,21 +3006,21 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi)
                 * 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.
+                * A proper fix would be to always have proper inset positions
+                * at this point.
                 */
                // 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);
+               RowPainter rp(pi, buffer().text(), 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_;
        }
 
+       // Current x position of the cursor in pixels
+       int cur_x = getPos(d->cursor_).x_;
+
        // Horizontal scroll offset of the cursor row in pixels
        int offset = d->horiz_scroll_offset_;
        int const MARGIN = 2 * theFontMetrics(d->cursor_.real_current_font).em()