]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Revert "Fixup 0cbe0d7a: avoid double redraw when completion is finished"
[lyx.git] / src / BufferView.cpp
index 023301dd482e596d77e674ac597d9a022288304f..ae0c71461a2876caad4b5f6278c5f34eb51b5de3 100644 (file)
@@ -20,6 +20,7 @@
 #include "Buffer.h"
 #include "BufferList.h"
 #include "BufferParams.h"
+#include "BiblioInfo.h"
 #include "CoordCache.h"
 #include "Cursor.h"
 #include "CutAndPaste.h"
@@ -38,6 +39,7 @@
 #include "MetricsInfo.h"
 #include "Paragraph.h"
 #include "Session.h"
+#include "texstream.h"
 #include "Text.h"
 #include "TextMetrics.h"
 #include "TexRow.h"
@@ -47,6 +49,7 @@
 #include "insets/InsetCitation.h"
 #include "insets/InsetCommand.h" // ChangeRefs
 #include "insets/InsetGraphics.h"
+#include "insets/InsetIndex.h"
 #include "insets/InsetRef.h"
 #include "insets/InsetText.h"
 
@@ -67,6 +70,7 @@
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/docstring.h"
+#include "support/docstring_list.h"
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lassert.h"
@@ -182,7 +186,7 @@ bool gotoInset(BufferView * bv, vector<InsetCode> const & codes,
 
        tmpcur.clearSelection();
        bv->setCursor(tmpcur);
-       return bv->scrollToCursor(bv->cursor(), false, true);
+       return bv->scrollToCursor(bv->cursor(), SCROLL_TOP);
 }
 
 
@@ -292,6 +296,8 @@ struct BufferView::Private
        bool clickable_inset_;
        /// shape of the caret
        frontend::CaretGeometry caret_geometry_;
+       ///
+       bool mouse_selecting_ = false;
 };
 
 
@@ -340,11 +346,14 @@ int BufferView::defaultMargin() const
 
 int BufferView::rightMargin() const
 {
-       // The additional test for the case the outliner is opened.
-       if (full_screen_ && lyxrc.full_screen_limit)
-               return max(defaultMargin(), (width_ - lyxrc.full_screen_width) / 2);
+       const int screen_width = inPixels(lyxrc.screen_width);
 
-       return defaultMargin();
+       // The additional test for the case the outliner is opened.
+       if (!lyxrc.screen_limit || width_ < screen_width + 2 * defaultMargin()) {
+               return defaultMargin();
+       } else {
+               return (width_ - screen_width) / 2;
+       }
 }
 
 
@@ -541,13 +550,13 @@ void BufferView::processUpdateFlags(Update::flags flags)
                if (needsFitCursor()) {
                        // First try to make the selection start visible
                        // (which is just the cursor when there is no selection)
-                       scrollToCursor(d->cursor_.selectionBegin(), false, false);
+                       scrollToCursor(d->cursor_.selectionBegin(), SCROLL_VISIBLE);
                        // Metrics have to be recomputed (maybe again)
                        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, false);
+                               scrollToCursor(d->cursor_, SCROLL_VISIBLE);
                                // Metrics have to be recomputed (maybe again)
                                updateMetrics(flags);
                        }
@@ -741,7 +750,7 @@ void BufferView::scrollDocView(int const pixels, bool update)
        // cut off at the top
        if (pixels <= d->scrollbarParameters_.min) {
                DocIterator dit = doc_iterator_begin(&buffer_);
-               showCursor(dit, false, false, update);
+               showCursor(dit, SCROLL_VISIBLE, update);
                LYXERR(Debug::SCROLLING, "scroll to top");
                return;
        }
@@ -750,7 +759,7 @@ void BufferView::scrollDocView(int const pixels, bool update)
        if (pixels >= d->scrollbarParameters_.max) {
                DocIterator dit = doc_iterator_end(&buffer_);
                dit.backwardPos();
-               showCursor(dit, false, false, update);
+               showCursor(dit, SCROLL_VISIBLE, update);
                LYXERR(Debug::SCROLLING, "scroll to bottom");
                return;
        }
@@ -775,7 +784,7 @@ void BufferView::scrollDocView(int const pixels, bool update)
        DocIterator dit = doc_iterator_begin(&buffer_);
        dit.pit() = i;
        LYXERR(Debug::SCROLLING, "pixels = " << pixels << " -> scroll to pit " << i);
-       showCursor(dit, false, false, update);
+       showCursor(dit, SCROLL_VISIBLE, update);
 }
 
 
@@ -961,34 +970,36 @@ int BufferView::workWidth() const
 
 void BufferView::recenter()
 {
-       showCursor(d->cursor_, true, false, true);
+       showCursor(d->cursor_, SCROLL_CENTER, true);
 }
 
 
 void BufferView::showCursor()
 {
-       showCursor(d->cursor_, false, false, true);
+       showCursor(d->cursor_, SCROLL_VISIBLE, true);
 }
 
 
-void BufferView::showCursor(DocIterator const & dit,
-       bool recenter, bool force, bool update)
+void BufferView::showCursor(DocIterator const & dit, ScrollType how,
+       bool update)
 {
-       if (scrollToCursor(dit, recenter, force) && update)
+       if (scrollToCursor(dit, how) && update)
                processUpdateFlags(Update::Force);
 }
 
 
-bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter, bool force)
+bool BufferView::scrollToCursor(DocIterator const & dit, ScrollType how)
 {
        // We are not properly started yet, delay until resizing is done.
        if (height_ == 0)
                return false;
 
-       if (recenter)
-               LYXERR(Debug::SCROLLING, "recentering and scrolling to cursor");
+       if (how == SCROLL_CENTER)
+               LYXERR(Debug::SCROLLING, "Centering cursor in workarea");
+       else if (how == SCROLL_TOP)
+               LYXERR(Debug::SCROLLING, "Setting cursor to top of workarea");
        else
-               LYXERR(Debug::SCROLLING, "scrolling to cursor");
+               LYXERR(Debug::SCROLLING, "Making sure cursor is visible in workarea");
 
        CursorSlice const & bot = dit.bottom();
        TextMetrics & tm = textMetrics(bot.text());
@@ -1007,7 +1018,7 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter, bo
        else if (bot_pit == tm.last().first + 1)
                tm.newParMetricsDown();
 
-       if (tm.contains(bot_pit) && !force) {
+       if (tm.contains(bot_pit) && how == SCROLL_VISIBLE) {
                ParagraphMetrics const & pm = tm.parMetrics(bot_pit);
                LBUFERR(!pm.rows().empty());
                // FIXME: smooth scrolling doesn't work in mathed.
@@ -1018,14 +1029,12 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter, bo
                Dimension const & row_dim =
                        inner_pm.getRow(cs.pos(), dit.boundary()).dim();
                int scrolled = 0;
-               if (recenter)
-                       scrolled = scroll(ypos - height_/2);
 
                // We try to visualize the whole row, if the row height is larger than
                // the screen height, we scroll to a heuristic value of height_ / 4.
                // FIXME: This heuristic value should be replaced by a recursive search
                // for a row in the inset that can be visualized completely.
-               else if (row_dim.height() > height_) {
+               if (row_dim.height() > height_) {
                        if (ypos < defaultRowHeight())
                                scrolled = scroll(ypos - height_ / 4);
                        else if (ypos > height_ - defaultRowHeight())
@@ -1054,28 +1063,21 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter, bo
                d->inlineCompletionPos_ = DocIterator();
 
        tm.redoParagraph(bot_pit);
-       ParagraphMetrics const & pm = tm.parMetrics(bot_pit);
        int const offset = coordOffset(dit).y_;
-
+       pit_type const old_pit = d->anchor_pit_;
        d->anchor_pit_ = bot_pit;
+
        CursorSlice const & cs = dit.innerTextSlice();
        ParagraphMetrics const & inner_pm =
                textMetrics(cs.text()).parMetrics(cs.pit());
        Dimension const & row_dim =
                inner_pm.getRow(cs.pos(), dit.boundary()).dim();
 
-       if (recenter)
-               d->anchor_ypos_ = height_/2;
-       else if (d->anchor_pit_ == 0)
-               d->anchor_ypos_ = offset + pm.ascent();
-       else if (d->anchor_pit_ == max_pit)
-               d->anchor_ypos_ = height_ - offset - row_dim.descent();
-       else if (offset > height_)
-               d->anchor_ypos_ = height_ - offset - row_dim.descent();
-       else
-               d->anchor_ypos_ = row_dim.ascent();
-
-       return true;
+       int const old_ypos = d->anchor_ypos_;
+       d->anchor_ypos_ = - offset + row_dim.ascent();
+       if (how == SCROLL_CENTER)
+               d->anchor_ypos_ += height_/2 - row_dim.height() / 2;
+       return d->anchor_ypos_ != old_ypos || d->anchor_pit_ != old_pit;
 }
 
 
@@ -1089,8 +1091,6 @@ void BufferView::makeDocumentClass()
 
 void BufferView::updateDocumentClass(DocumentClassConstPtr olddc)
 {
-       message(_("Converting document to new document class..."));
-
        StableDocIterator backcur(d->cursor_);
        ErrorList & el = buffer_.errorList("Class Switch");
        cap::switchBetweenClasses(
@@ -1218,6 +1218,7 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
        case LFUN_SCREEN_SHOW_CURSOR:
        case LFUN_BIBTEX_DATABASE_ADD:
        case LFUN_BIBTEX_DATABASE_DEL:
+       case LFUN_BIBTEX_DATABASE_LIST:
        case LFUN_STATISTICS:
        case LFUN_KEYMAP_OFF:
        case LFUN_KEYMAP_PRIMARY:
@@ -1581,7 +1582,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                                        success = setCursorFromEntries({id, pos},
                                                                       {id_end, pos_end});
                                }
-                               if (success && scrollToCursor(d->cursor_, false, true))
+                               if (success && scrollToCursor(d->cursor_, SCROLL_TOP))
                                                dr.screenUpdate(Update::Force);
                        } else {
                                // Switch to other buffer view and resend cmd
@@ -1719,6 +1720,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                }
                if (cur.selection())
                        pattern = cur.selectionAsString(false);
+               else if (!cur.inTexted())
+                       break; // not suitable for selectWord at cursor
                else {
                        pos_type spos = cur.pos();
                        cur.innerText()->selectWord(cur, WHOLE_WORD);
@@ -1755,6 +1758,78 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                break;
        }
 
+       case LFUN_INDEX_TAG_ALL: {
+               Inset * ins = cur.nextInset();
+               if (!ins || ins->lyxCode() != INDEX_CODE)
+                       // not at index inset
+                       break;
+
+               // clone the index inset
+               InsetIndex * cins =
+                       new InsetIndex(static_cast<InsetIndex &>(*cur.nextInset()));
+               // In order to avoid duplication, we compare the
+               // LaTeX output if we find another index inset after
+               // the word
+               odocstringstream oilatex;
+               otexstream oits(oilatex);
+               OutputParams rp(&cur.buffer()->params().encoding());
+               ins->latex(oits, rp);
+               cap::copyInsetToTemp(cur, cins);
+
+               // move backwards into preceding word
+               // skip over other index insets
+               cur.backwardPosIgnoreCollapsed();
+               while (true) {
+                       if (cur.inset().lyxCode() == INDEX_CODE)
+                               cur.pop_back();
+                       else if (cur.prevInset() && cur.prevInset()->lyxCode() == INDEX_CODE)
+                               cur.backwardPosIgnoreCollapsed();
+                       else
+                               break;
+               }
+               if (!cur.inTexted()) {
+                       // Nothing to do here.
+                       setCursorFromInset(ins);
+                       break;
+               }
+               // Get word or selection
+               cur.text()->selectWord(cur, WHOLE_WORD);
+               docstring const searched_string = cur.selectionAsString(false);
+               // Start from the beginning
+               lyx::dispatch(FuncRequest(LFUN_BUFFER_BEGIN));
+               while (findOne(this, searched_string,
+                              false,// case sensitive
+                              true,// match whole word only
+                              true,// forward
+                              false,//find deleted
+                              false,//check wrap
+                              false,// auto-wrap
+                              false,// instant
+                              false// only selection
+                              )) {
+                       cur.clearSelection();
+                       Inset * ains = cur.nextInset();
+                       if (ains && ains->lyxCode() == INDEX_CODE) {
+                               // We have an index inset.
+                               // Check whether it has the same
+                               // LaTeX content and move on if so.
+                               odocstringstream filatex;
+                               otexstream fits(filatex);
+                               ains->latex(fits, rp);
+                               if (oilatex.str() == filatex.str())
+                                       continue;
+                       }
+                       // Paste the inset and possibly continue
+                       cap::pasteFromTemp(cursor(), cursor().buffer()->errorList("Paste"));
+               }
+               // Go back to start position.
+               setCursorFromInset(ins);
+               dr.screenUpdate(cur.result().screenUpdate());
+               if (cur.result().needBufferUpdate())
+                       dr.forceBufferUpdate();
+               break;
+       }
+
        case LFUN_MARK_OFF:
                cur.clearSelection();
                dr.setMessage(from_utf8(N_("Mark off")));
@@ -1849,6 +1924,25 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                break;
        }
 
+       case LFUN_BIBTEX_DATABASE_LIST: {
+               docstring_list const & files = buffer_.getBibfiles();
+               bool first = true;
+               docstring result;
+               char const separator(os::path_separator());
+               for (auto const & file : files) {
+                       if (first)
+                               first = false;
+                       else
+                               result += separator;
+
+                       FileName const fn = buffer_.getBibfilePath(file);
+                       string const path = fn.realPath();
+                       result += from_utf8(os::external_path(path));
+               }
+               dr.setMessage(result);
+               break;
+       }
+
        case LFUN_STATISTICS: {
                DocIterator from, to;
                if (cur.selection()) {
@@ -1874,16 +1968,14 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                        message += _("One word");
                message += "\n";
                if (chars_blanks != 1)
-                       message += bformat(_("%1$d characters (including blanks)"),
-                                         chars_blanks);
+                       message += bformat(_("%1$d characters"), chars_blanks);
                else
-                       message += _("One character (including blanks)");
+                       message += _("One character");
                message += "\n";
                if (chars != 1)
-                       message += bformat(_("%1$d characters (excluding blanks)"),
-                                         chars);
+                       message += bformat(_("%1$d characters (no blanks)"), chars);
                else
-                       message += _("One character (excluding blanks)");
+                       message += _("One character (no blanks)");
 
                Alert::information(_("Statistics"), message);
        }
@@ -2204,6 +2296,28 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
                string icstr = InsetCommand::params2string(icp);
                FuncRequest fr(LFUN_INSET_INSERT, icstr);
                lyx::dispatch(fr);
+
+               // if the request comes from the LyX server, then we
+               // return a list of the undefined keys, in case some
+               // action could be taken.
+               if (cmd.origin() != FuncRequest::LYXSERVER)
+                       break;
+
+               vector<docstring> keys = getVectorFromString(from_utf8(arg));
+               vector<docstring>::iterator it = keys.begin();
+               vector<docstring>::const_iterator end = keys.end();
+
+               BiblioInfo const & bibInfo = buffer_.masterBibInfo();
+               const BiblioInfo::const_iterator bibEnd = bibInfo.end();
+               while (it != end) {
+                       if (bibInfo.find(*it) != bibEnd) {
+                               it = keys.erase(it);
+                               end = keys.end();
+                       } else
+                               ++it;
+               }
+               dr.setMessage(getStringFromVector(keys));
+
                break;
        }
 
@@ -2468,6 +2582,12 @@ void BufferView::clearLastInset(Inset * inset) const
 }
 
 
+bool BufferView::mouseSelecting() const
+{
+       return d->mouse_selecting_;
+}
+
+
 void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
 {
        //lyxerr << "[ cmd0 " << cmd0 << "]" << endl;
@@ -2490,6 +2610,9 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
        d->mouse_position_cache_.x_ = cmd.x();
        d->mouse_position_cache_.y_ = cmd.y();
 
+       d->mouse_selecting_ =
+               cmd.action() == LFUN_MOUSE_MOTION && cmd.button() == mouse_button::button1;
+
        if (cmd.action() == LFUN_MOUSE_MOTION && cmd.button() == mouse_button::none) {
                updateHoveredInset();
                return;
@@ -2531,8 +2654,8 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
 
        // Notify left insets
        if (cur != old) {
-               bool badcursor = old.fixIfBroken() | cur.fixIfBroken();
-               badcursor |= notifyCursorLeavesOrEnters(old, cur);
+               bool badcursor = old.fixIfBroken() || cur.fixIfBroken();
+               badcursor = badcursor || notifyCursorLeavesOrEnters(old, cur);
                if (badcursor)
                        cursor().fixIfBroken();
        }
@@ -2621,7 +2744,7 @@ bool BufferView::setCursorFromRow(int row)
 {
        TexRow::TextEntry start, end;
        tie(start,end) = buffer_.texrow().getEntriesFromRow(row);
-       LYXERR(Debug::LATEX,
+       LYXERR(Debug::OUTFILE,
               "setCursorFromRow: for row " << row << ", TexRow has found "
               "start (id=" << start.id << ",pos=" << start.pos << "), "
               "end (id=" << end.id << ",pos=" << end.pos << ")");