]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Amend 6c3447c8: FindAdv: sometimes a space is added on some math symbols
[lyx.git] / src / BufferView.cpp
index f0e3704064acf008e91a36977aa2d44e1cf3db3c..755e2f7b4e1802defb1b6afc4517e181a0dcf22d 100644 (file)
@@ -31,7 +31,6 @@
 #include "Intl.h"
 #include "Language.h"
 #include "LayoutFile.h"
-#include "Lexer.h"
 #include "LyX.h"
 #include "LyXAction.h"
 #include "lyxfind.h"
@@ -75,6 +74,7 @@
 #include "support/gettext.h"
 #include "support/lassert.h"
 #include "support/Length.h"
+#include "support/Lexer.h"
 #include "support/lstrings.h"
 #include "support/lyxlib.h"
 #include "support/types.h"
@@ -214,7 +214,7 @@ struct BufferView::Private
        Private(BufferView & bv) :
                update_strategy_(FullScreenUpdate),
                update_flags_(Update::Force),
-               cursor_(bv), anchor_pit_(0), anchor_ypos_(0),
+               cursor_(bv), anchor_pit_(0), anchor_ypos_(10000),
                wh_(0), inlineCompletionUniqueChars_(0),
                last_inset_(nullptr), mouse_position_cache_(),
                gui_(nullptr), bookmark_edit_position_(-1),
@@ -298,6 +298,13 @@ struct BufferView::Private
        frontend::CaretGeometry caret_geometry_;
        ///
        bool mouse_selecting_ = false;
+       /// Reference value for statistics (essentially subtract this from the actual value to see relative counts)
+       /// (words/chars/chars no blanks)
+       int stats_ref_value_w_ = 0;
+       int stats_ref_value_c_ = 0;
+       int stats_ref_value_nb_ = 0;
+       bool stats_update_trigger_ = false;
+
 };
 
 
@@ -532,7 +539,7 @@ void BufferView::processUpdateFlags(Update::flags flags)
                   << flagsAsString(flags) << ")  buffer: " << &buffer_);
 
        // Case when no explicit update is requested.
-       if (flags == Update::None)
+       if (flags == Update::None || !ready())
                return;
 
        /* FIXME We would like to avoid doing this here, since it is very
@@ -549,36 +556,40 @@ void BufferView::processUpdateFlags(Update::flags flags)
                updateMetrics(true);
                // metrics is done, full drawing is necessary now
                flags = (flags & ~Update::Force) | Update::ForceDraw;
-       } else if (flags & Update::ForceDraw)
+       }
+       /* If a single paragraph update has been requested and we are not
+        * already repainting all, check whether this update changes the
+        * paragraph metrics. If it does, then compute all metrics (in
+        * case the paragraph is in an inset)
+        *
+        * We handle this before FitCursor because the later will require
+        * correct metrics at cursor position.
+        */
+       else if ((flags & Update::SinglePar) && !(flags & Update::ForceDraw)) {
+               if (!singleParUpdate())
+                       updateMetrics(true);
+       }
+       else if (flags & Update::ForceDraw)
                // This will compute only the needed metrics and update positions.
                updateMetrics(false);
 
-       // Detect whether we can only repaint a single paragraph (if we
-       // are not already redrawing all).
-       // We handle this before FitCursor because the later will require
-       // correct metrics at cursor position.
-       if (!(flags & Update::ForceDraw)
-                       && (flags & Update::SinglePar)
-                       && !singleParUpdate())
-               updateMetrics(true);
-
        // Then make sure that the screen contains the cursor if needed
        if (flags & Update::FitCursor) {
                if (needsFitCursor()) {
                        // First try to make the selection start visible
                        // (which is just the cursor when there is no selection)
                        scrollToCursor(d->cursor_.selectionBegin(), SCROLL_VISIBLE);
-                       // Metrics have to be recomputed (maybe again)
-                       updateMetrics(true);
+                       // Metrics have to be updated
+                       updateMetrics(false);
                        // 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_, SCROLL_VISIBLE);
                                // Metrics have to be recomputed (maybe again)
-                               updateMetrics(true);
+                               updateMetrics(false);
                        }
                }
-               flags = flags & ~Update::FitCursor;
+               flags = (flags & ~Update::FitCursor) | Update::ForceDraw;
        }
 
        // Add flags to the the update flags. These will be reset to None
@@ -611,7 +622,7 @@ void BufferView::processUpdateFlags(Update::flags flags)
 
 void BufferView::updateScrollbarParameters()
 {
-       if (height_ == 0 && width_ == 0)
+       if (!ready())
                return;
 
        // We prefer fixed size line scrolling.
@@ -1006,7 +1017,7 @@ void BufferView::showCursor(DocIterator const & dit, ScrollType how,
        bool update)
 {
        if (scrollToCursor(dit, how) && update)
-               processUpdateFlags(Update::Force);
+               processUpdateFlags(Update::ForceDraw);
 }
 
 
@@ -1343,6 +1354,17 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                flag.setEnabled(cur.selection());
                break;
 
+       case LFUN_STATISTICS_REFERENCE_CLAMP: {
+               // disable optitem reset if clamp not used
+               if  (cmd.argument() == "reset" && d->stats_ref_value_c_ == 0) {
+                               flag.setEnabled(false);
+                               break;
+               }
+               flag.setEnabled(true);
+               break;
+
+       }
+
        default:
                return false;
        }
@@ -2014,6 +2036,25 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
        }
                break;
 
+       case LFUN_STATISTICS_REFERENCE_CLAMP: {
+               d->stats_update_trigger_ = true;
+               if  (cmd.argument() == "reset") {
+                       d->stats_ref_value_w_ = d->stats_ref_value_c_ = d->stats_ref_value_nb_ = 0;
+                       break;
+               }
+
+               DocIterator from, to;
+               from = doc_iterator_begin(&buffer_);
+               to = doc_iterator_end(&buffer_);
+               buffer_.updateStatistics(from, to);
+
+               d->stats_ref_value_w_ = buffer_.wordCount();
+               d->stats_ref_value_c_ = buffer_.charCount(true);
+               d->stats_ref_value_nb_ = buffer_.charCount(false);
+               break;
+       }
+
+
        case LFUN_SCREEN_UP:
        case LFUN_SCREEN_DOWN: {
                Point p = getPos(cur);
@@ -2484,14 +2525,19 @@ void BufferView::clearSelection()
 
 void BufferView::resize(int width, int height)
 {
-       // Update from work area
-       width_ = width;
        height_ = height;
+       // Update metrics only if width has changed
+       if (width != width_) {
+               width_ = width;
 
-       // Clear the paragraph height cache.
-       d->par_height_.clear();
-       // Redo the metrics.
-       updateMetrics();
+               // Clear the paragraph height cache.
+               d->par_height_.clear();
+               // Redo the metrics.
+               updateMetrics(true);
+       }
+       // metrics is OK, full drawing is necessary now
+       d->update_flags_ = (d->update_flags_ & ~Update::Force) | Update::ForceDraw;
+       d->update_strategy_ = FullScreenUpdate;
 }
 
 
@@ -2621,19 +2667,35 @@ bool BufferView::mouseSelecting() const
 }
 
 
+int BufferView::stats_ref_value_w() const
+{
+       return d->stats_ref_value_w_;
+}
+
+
+int BufferView::stats_ref_value_c() const
+{
+       return d->stats_ref_value_c_;
+}
+
+
+int BufferView::stats_ref_value_nb() const
+{
+       return d->stats_ref_value_nb_;
+}
+
+
 void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
 {
        //lyxerr << "[ cmd0 " << cmd0 << "]" << endl;
 
+       if (!ready())
+               return;
+
        // This is only called for mouse related events including
        // LFUN_FILE_OPEN generated by drag-and-drop.
        FuncRequest cmd = cmd0;
 
-       Cursor old = cursor();
-       Cursor cur(*this);
-       cur.push(buffer_.inset());
-       cur.selection(d->cursor_.selection());
-
        // Either the inset under the cursor or the
        // surrounding Text will handle this event.
 
@@ -2651,6 +2713,11 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
                return;
        }
 
+       Cursor old = cursor();
+       Cursor cur(*this);
+       cur.push(buffer_.inset());
+       cur.selection(d->cursor_.selection());
+
        // Build temporary cursor.
        Inset * inset = d->text_metrics_[&buffer_.text()].editXY(cur, cmd.x(), cmd.y());
        if (inset) {
@@ -3125,9 +3192,11 @@ void BufferView::updateMetrics()
 
 void BufferView::updateMetrics(bool force)
 {
-       if (height_ == 0 || width_ == 0)
+       if (!ready())
                return;
 
+       //LYXERR0("updateMetrics " << _v_(force));
+
        Text & buftext = buffer_.text();
        pit_type const lastpit = int(buftext.paragraphs().size()) - 1;
 
@@ -3142,6 +3211,7 @@ void BufferView::updateMetrics(bool force)
                d->text_metrics_.clear();
        }
 
+       // This should not be moved earlier
        TextMetrics & tm = textMetrics(&buftext);
 
        // make sure inline completion pointer is ok
@@ -3157,14 +3227,16 @@ void BufferView::updateMetrics(bool force)
 
        // Check that the end of the document is not too high
        int const min_visible = lyxrc.scroll_below_document ? minVisiblePart() : height_;
-       if (tm.last().first == lastpit && tm.last().second->bottom() < min_visible) {
+       if (tm.last().first == lastpit && tm.last().second->hasPosition()
+            && tm.last().second->bottom() < min_visible) {
                d->anchor_ypos_ += min_visible - tm.last().second->bottom();
                LYXERR(Debug::SCROLLING, "Too high, adjusting anchor ypos to " << d->anchor_ypos_);
                tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
        }
 
        // Check that the start of the document is not too low
-       if (tm.first().first == 0 && tm.first().second->top() > 0) {
+       if (tm.first().first == 0 && tm.first().second->hasPosition()
+            && tm.first().second->top() > 0) {
                d->anchor_ypos_ -= tm.first().second->top();
                LYXERR(Debug::SCROLLING, "Too low, adjusting anchor ypos to " << d->anchor_ypos_);
                tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
@@ -3172,16 +3244,16 @@ void BufferView::updateMetrics(bool force)
 
        /* FIXME: do we want that? It avoids potential issues with old
         * paragraphs that should have been recomputed but have not, at
-        * the price of potential extra metrics computaiton. I do not
+        * the price of potential extra metrics computation. I do not
         * think that the performance gain is high, so that for now the
         * extra paragraphs are removed
         */
        // Remove paragraphs that are outside of screen
-       while(tm.first().second->bottom() <= 0) {
+       while(!tm.first().second->hasPosition() || tm.first().second->bottom() <= 0) {
                //LYXERR0("Forget pit: " << tm.first().first);
                tm.forget(tm.first().first);
        }
-       while(tm.last().second->top() > height_) {
+       while(!tm.last().second->hasPosition() || tm.last().second->top() > height_) {
                //LYXERR0("Forget pit: " << tm.first().first);
                tm.forget(tm.last().first);
        }
@@ -3586,7 +3658,7 @@ bool BufferView::busy() const
 
 void BufferView::draw(frontend::Painter & pain, bool paint_caret)
 {
-       if (height_ == 0 || width_ == 0)
+       if (!ready())
                return;
        LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t--- START NODRAW ---"
                                 : "\t\t*** START DRAWING ***"));
@@ -3646,7 +3718,11 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
                // Draw everything.
                tm.draw(pi, 0, y);
 
-               // and possibly grey out below
+               break;
+       }
+
+       // Possibly grey out below
+       if (d->update_strategy_ != NoScreenUpdate) {
                pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
                int const y2 = lastpm.second->bottom();
 
@@ -3655,8 +3731,8 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
                                ? Color_background : Color_bottomarea;
                        pain.fillRectangle(0, y2, width_, height_ - y2, color);
                }
-               break;
        }
+
        LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t --- END NODRAW ---"
                                : "\t\t *** END DRAWING ***"));
 
@@ -3876,4 +3952,14 @@ bool BufferView::clickableInset() const
        return d->clickable_inset_;
 }
 
+
+bool BufferView::stats_update_trigger()
+{
+       if (d->stats_update_trigger_) {
+               d->stats_update_trigger_ = false;
+               return true;
+       }
+       return false;
+}
+
 } // namespace lyx