commit 1cc14a31ca8320d881b674f93c34a09cf1666cca
Author: Guillaume Munch <g...@lyx.org>
Date:   Mon May 30 21:42:08 2016 +0100

    TocWidget: fix an erroneous collapse and optimise updates based on profiling
    
    TocModels::reset() in GuiView::structureChanged() collapses the TocWidget, 
and
    therefore requires an update right after, which was missing.
    
    In fact, profiling TocWidget::updateView() shows that delaying the update is
    good only for fast keypresses (essentially movement). It costs 5% of a
    char-forward operation in a document with approx. 100 table of contents
    items. The update optimisation has been rewritten to take this data into
    account.

diff --git a/src/frontends/qt4/GuiToc.cpp b/src/frontends/qt4/GuiToc.cpp
index 48349fc..29ec85c 100644
--- a/src/frontends/qt4/GuiToc.cpp
+++ b/src/frontends/qt4/GuiToc.cpp
@@ -67,7 +67,6 @@ void GuiToc::dispatchParams()
 
 void GuiToc::enableView(bool enable)
 {
-       widget_->checkModelChanged();
        if (!enable)
                // In the opposite case, updateView() will be called anyway.
                widget_->updateViewNow();
diff --git a/src/frontends/qt4/TocWidget.cpp b/src/frontends/qt4/TocWidget.cpp
index e98786b..c30d644 100644
--- a/src/frontends/qt4/TocWidget.cpp
+++ b/src/frontends/qt4/TocWidget.cpp
@@ -45,8 +45,7 @@ namespace frontend {
 
 TocWidget::TocWidget(GuiView & gui_view, QWidget * parent)
        : QWidget(parent), depth_(0), persistent_(false), gui_view_(gui_view),
-         update_timer_short_(new QTimer(this)),
-         update_timer_long_(new QTimer(this))
+         timer_(new QTimer(this))
 {
        setupUi(this);
 
@@ -88,21 +87,8 @@ TocWidget::TocWidget(GuiView & gui_view, QWidget * parent)
                this, SLOT(filterContents()));
 
        // setting the update timer
-       update_timer_short_->setSingleShot(true);
-       update_timer_long_->setSingleShot(true);
-       update_timer_short_->setInterval(0);
-       update_timer_long_->setInterval(2000);
-       connect(update_timer_short_, SIGNAL(timeout()),
-               this, SLOT(realUpdateView()));
-       connect(update_timer_long_, SIGNAL(timeout()),
-               this, SLOT(realUpdateView()));
-
-       // fix #9826: Outline disclosure of subsection content disappears one 
second
-       // after doubleclicking content item.
-       // This is only meant as a workaround. See #6675 for more general issues
-       // regarding unwanted collapse of the tree view.
-       connect(tocTV, SIGNAL(expanded(const QModelIndex &)),
-               update_timer_long_, SLOT(stop()));
+       timer_->setSingleShot(true);
+       connect(timer_, SIGNAL(timeout()), this, SLOT(finishUpdateView()));
 
        init(QString());
 }
@@ -396,26 +382,6 @@ void TocWidget::enableControls(bool enable)
 
 void TocWidget::updateView()
 {
-       // Subtler optimization for having the delay more UI invisible.
-       // We trigger update immediately for sparse editation actions,
-       // i.e. there was no editation/cursor movement in last 2 sec.
-       // At worst there will be +1 redraw after 2s in a such "calm" mode.
-       if (!update_timer_long_->isActive())
-               update_timer_short_->start();
-       // resets the timer to trigger after 2s
-       update_timer_long_->start();
-}
-
-
-void TocWidget::updateViewNow()
-{
-       update_timer_long_->stop();
-       update_timer_short_->start();
-}
-
-
-void TocWidget::realUpdateView()
-{
        if (!gui_view_.documentBufferView()) {
                tocTV->setModel(0);
                depthSL->setMaximum(0);
@@ -426,7 +392,7 @@ void TocWidget::realUpdateView()
        setEnabled(true);
        bool const is_sortable = isSortable();
        sortCB->setEnabled(is_sortable);
-       bool focus_ = tocTV->hasFocus();
+       bool focus = tocTV->hasFocus();
        tocTV->setEnabled(false);
        tocTV->setUpdatesEnabled(false);
 
@@ -444,8 +410,7 @@ void TocWidget::realUpdateView()
                && gui_view_.tocModels().isSorted(current_type_));
        sortCB->blockSignals(false);
 
-       bool const can_navigate_ = canNavigate();
-       persistentCB->setEnabled(can_navigate_);
+       persistentCB->setEnabled(canNavigate());
 
        bool controls_enabled = toc_model && toc_model->rowCount() > 0
                && !gui_view_.documentBufferView()->buffer().isReadonly();
@@ -453,25 +418,42 @@ void TocWidget::realUpdateView()
 
        depthSL->setMaximum(gui_view_.tocModels().depth(current_type_));
        depthSL->setValue(depth_);
-       if (!persistent_ && can_navigate_)
-               setTreeDepth(depth_);
-       if (can_navigate_) {
-               persistentCB->setChecked(persistent_);
-               select(gui_view_.tocModels().currentIndex(current_type_));
-       }
-       filterContents();
        tocTV->setEnabled(true);
        tocTV->setUpdatesEnabled(true);
-       if (focus_)
+       if (focus)
                tocTV->setFocus();
+
+       // Expensive operations are on a timer.  We finish the update 
immediately
+       // for sparse edition actions, i.e. there was no edition/cursor movement
+       // recently, then every 300ms.
+       if (!timer_->isActive()) {
+               finishUpdateView();
+               timer_->start(300);
+       }
 }
 
 
-void TocWidget::checkModelChanged()
+void TocWidget::updateViewNow()
 {
-       if (!gui_view_.documentBufferView() ||
-           gui_view_.tocModels().model(current_type_) != tocTV->model())
-               realUpdateView();
+       timer_->stop();
+       updateView();
+}
+
+
+void TocWidget::finishUpdateView()
+{
+       // Profiling shows that this is the expensive stuff in the context of 
typing
+       // text and moving with arrows (still five times less than 
updateToolbars in
+       // my tests with a medium-sized document, however this grows linearly 
in the
+       // size of the document). For bigger operations, this is negligible, and
+       // outweighted by TocModels::reset() anyway.
+       if (canNavigate()) {
+               if (!persistent_)
+                       setTreeDepth(depth_);
+               persistentCB->setChecked(persistent_);
+               select(gui_view_.tocModels().currentIndex(current_type_));
+       }
+       filterContents();
 }
 
 
@@ -543,6 +525,7 @@ void TocWidget::init(QString const & str)
        typeCO->blockSignals(true);
        typeCO->setCurrentIndex(new_index);
        typeCO->blockSignals(false);
+       updateViewNow();
 }
 
 } // namespace frontend
diff --git a/src/frontends/qt4/TocWidget.h b/src/frontends/qt4/TocWidget.h
index ec1d5ad..3f67606 100644
--- a/src/frontends/qt4/TocWidget.h
+++ b/src/frontends/qt4/TocWidget.h
@@ -43,13 +43,11 @@ public:
        ///
        bool getStatus(Cursor & cur, FuncRequest const & fr, FuncStatus & 
status)
                const;
-       // update the view when the model has changed
-       void checkModelChanged();
 
 public Q_SLOTS:
-       /// Schedule an update of the dialog after a delay
+       /// Schedule an update of the dialog, delaying expensive operations
        void updateView();
-       /// Schedule an update of the dialog immediately
+       /// Update completely without delay
        void updateViewNow();
 
 protected Q_SLOTS:
@@ -74,8 +72,8 @@ protected Q_SLOTS:
        void showContextMenu(const QPoint & pos);
 
 private Q_SLOTS:
-       /// Update the display of the dialog
-       void realUpdateView();
+       /// Perform the expensive update operations
+       void finishUpdateView();
 
 private:
        ///
@@ -108,12 +106,8 @@ private:
        bool persistent_;
        ///
        GuiView & gui_view_;
-       // Timers for scheduling updates: one immediately and one after a delay.
-       // This is according to the logic of the previous code: when at rest, 
the
-       // update is carried out immediately, and when an update was done 
recently,
-       // we schedule an update to occur 2s after resting.
-       QTimer * update_timer_short_;
-       QTimer * update_timer_long_;
+       // Timer for scheduling expensive update operations
+       QTimer * timer_;
 };
 
 } // namespace frontend

Reply via email to