From 8e6dbadef2e7f25caed42559c4ffc832e03d387b Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Sat, 11 Jul 2009 17:48:05 +0000 Subject: [PATCH] Fixed performance issues related to selections and deleting of files: - Don't connect to KDirLister::itemDeleted(const KFileItem&), but KDirLister::itemsDeleted(const KFileItemList&). Otherwise Dolphin is informed about each single file deletion instead of getting the deleted items as a list. Thanks to David Faure for the hint! - DolphinViewContainer::updateStatusBar() can be expensive when a lot of files are selected, as the file size must get retrieved. Assure that fast calls for updateStatusBar() don't trigger a synchronous update, do the update after 300 ms where no further update has been triggered. - Dolphin provides a list of file items when emitting the selectionChanged() signal. Collecting the file items is a quite expensive operation, so use the same approach as when updating the statusbar: only emit the selection changed signal when no change has been done within 300 ms. This improves the performance when doing huge selections a lot. - Make updateStatusBar() a private method, the main window should not need to take care about updating the statusbar (this is done internally now by DolphinViewContainer). BUG: 199090 BUG: 195787 CCBUG: 199352 CCBUG: 188218 svn path=/trunk/KDE/kdebase/apps/; revision=995015 --- src/dolphinmainwindow.cpp | 2 - src/dolphinview.cpp | 19 +++++++++- src/dolphinview.h | 15 ++++++++ src/dolphinviewcontainer.cpp | 72 ++++++++++++++++++++++-------------- src/dolphinviewcontainer.h | 22 ++++++++--- 5 files changed, 92 insertions(+), 38 deletions(-) diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 8796e6b0f..a95b5a0d2 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -274,8 +274,6 @@ void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection) compareFilesAction->setEnabled(false); } - m_activeViewContainer->updateStatusBar(); - emit selectionChanged(selection); } diff --git a/src/dolphinview.cpp b/src/dolphinview.cpp index d4dbbd2c2..4a81b12ea 100644 --- a/src/dolphinview.cpp +++ b/src/dolphinview.cpp @@ -98,6 +98,7 @@ DolphinView::DolphinView(QWidget* parent, m_columnView(0), m_fileItemDelegate(0), m_selectionModel(0), + m_selectionChangedTimer(0), m_dolphinModel(dolphinModel), m_dirLister(dirLister), m_proxyModel(proxyModel), @@ -188,7 +189,7 @@ void DolphinView::setActive(bool active) QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color(); if (active) { - emit selectionChanged(selectedItems()); + emitSelectionChangedSignal(); } else { color.setAlpha(150); } @@ -958,6 +959,14 @@ void DolphinView::triggerItem(const KFileItem& item) emit itemTriggered(item); // caught by DolphinViewContainer or DolphinPart } +void DolphinView::emitDelayedSelectionChangedSignal() +{ + // Invoke emitSelectionChangedSignal() with a delay of 300 ms. This assures + // that fast selection changes don't result in expensive operations to + // collect all file items for the signal (see DolphinView::selectedItems()). + m_selectionChangedTimer->start(); +} + void DolphinView::emitSelectionChangedSignal() { emit selectionChanged(DolphinView::selectedItems()); @@ -1436,6 +1445,12 @@ void DolphinView::createView() m_selectionModel = view->selectionModel(); } + m_selectionChangedTimer = new QTimer(this); + m_selectionChangedTimer->setSingleShot(true); + m_selectionChangedTimer->setInterval(300); + connect(m_selectionChangedTimer, SIGNAL(timeout()), + this, SLOT(emitSelectionChangedSignal())); + // reparent the selection model, as it should not be deleted // when deleting the model m_selectionModel->setParent(this); @@ -1454,7 +1469,7 @@ void DolphinView::createView() m_topLayout->insertWidget(1, view); connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), - this, SLOT(emitSelectionChangedSignal())); + this, SLOT(emitDelayedSelectionChangedSignal())); connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(emitContentsMoved())); connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)), diff --git a/src/dolphinview.h b/src/dolphinview.h index 24f56f403..44915f6c0 100644 --- a/src/dolphinview.h +++ b/src/dolphinview.h @@ -580,6 +580,19 @@ private slots: */ void triggerItem(const KFileItem& index); + /** + * Emits the signal \a selectionChanged() with a small delay. This is + * because getting all file items for the signal can be an expensive + * operation. Fast selection changes are collected in this case and + * the signal is emitted only after no selection change has been done + * within a small delay. + */ + void emitDelayedSelectionChangedSignal(); + + /** + * Is called by emitDelayedSelectionChangedSignal() and emits the + * signal \a selectionChanged() with all selected file items as parameter. + */ void emitSelectionChangedSignal(); /** @@ -785,7 +798,9 @@ private: DolphinDetailsView* m_detailsView; DolphinColumnView* m_columnView; DolphinFileItemDelegate* m_fileItemDelegate; + QItemSelectionModel* m_selectionModel; + QTimer* m_selectionChangedTimer; DolphinModel* m_dolphinModel; KDirLister* m_dirLister; diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index d8f90f357..356ff274e 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -75,6 +75,7 @@ DolphinViewContainer::DolphinViewContainer(DolphinMainWindow* mainWindow, m_view(0), m_filterBar(0), m_statusBar(0), + m_statusBarTimer(0), m_dirLister(0), m_proxyModel(0) { @@ -113,11 +114,11 @@ DolphinViewContainer::DolphinViewContainer(DolphinMainWindow* mainWindow, m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); connect(m_dirLister, SIGNAL(clear()), - this, SLOT(updateStatusBar())); + this, SLOT(delayedStatusBarUpdate())); connect(m_dirLister, SIGNAL(percent(int)), this, SLOT(updateProgress(int))); - connect(m_dirLister, SIGNAL(deleteItem(const KFileItem&)), - this, SLOT(updateStatusBar())); + connect(m_dirLister, SIGNAL(itemsDeleted(const KFileItemList&)), + this, SLOT(delayedStatusBarUpdate())); connect(m_dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted())); connect(m_dirLister, SIGNAL(infoMessage(const QString&)), @@ -152,6 +153,8 @@ DolphinViewContainer::DolphinViewContainer(DolphinMainWindow* mainWindow, this, SLOT(saveRootUrl(const KUrl&))); connect(m_view, SIGNAL(redirection(KUrl, KUrl)), this, SLOT(redirect(KUrl, KUrl))); + connect(m_view, SIGNAL(selectionChanged(const KFileItemList&)), + this, SLOT(delayedStatusBarUpdate())); connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)), this, SLOT(restoreView(const KUrl&))); @@ -159,6 +162,11 @@ DolphinViewContainer::DolphinViewContainer(DolphinMainWindow* mainWindow, this, SLOT(slotHistoryChanged())); m_statusBar = new DolphinStatusBar(this, m_view); + m_statusBarTimer = new QTimer(this); + m_statusBarTimer->setSingleShot(true); + m_statusBarTimer->setInterval(300); + connect(m_statusBarTimer, SIGNAL(timeout()), + this, SLOT(updateStatusBar())); m_filterBar = new FilterBar(this); m_filterBar->setVisible(settings->filterBar()); @@ -246,6 +254,37 @@ bool DolphinViewContainer::isUrlEditable() const return m_urlNavigator->isUrlEditable(); } +void DolphinViewContainer::delayedStatusBarUpdate() +{ + // Invoke updateStatusBar() with a small delay. This assures that + // when a lot of delayedStatusBarUpdates() are done in a short time, + // no bottleneck is given. + m_statusBarTimer->start(); +} + +void DolphinViewContainer::updateStatusBar() +{ + // As the item count information is less important + // in comparison with other messages, it should only + // be shown if: + // - the status bar is empty or + // - shows already the item count information or + // - shows only a not very important information + // - if any progress is given don't show the item count info at all + const QString msg(m_statusBar->message()); + const bool updateStatusBarMsg = (msg.isEmpty() + || (msg == m_statusBar->defaultText()) + || (m_statusBar->type() == DolphinStatusBar::Information)) + && (m_statusBar->progress() == 100); + + const QString text(m_view->statusBarText()); + m_statusBar->setDefaultText(text); + + if (updateStatusBarMsg) { + m_statusBar->setMessage(text, DolphinStatusBar::Default); + } +} + void DolphinViewContainer::updateProgress(int percent) { if (!m_showProgress) { @@ -274,7 +313,7 @@ void DolphinViewContainer::slotDirListerCompleted() m_showProgress = false; } - updateStatusBar(); + delayedStatusBarUpdate(); QMetaObject::invokeMethod(this, "restoreContentsPos", Qt::QueuedConnection); // Enable the 'File'->'Create New...' menu only if the directory @@ -325,33 +364,10 @@ void DolphinViewContainer::closeFilterBar() emit showFilterBarChanged(false); } -void DolphinViewContainer::updateStatusBar() -{ - // As the item count information is less important - // in comparison with other messages, it should only - // be shown if: - // - the status bar is empty or - // - shows already the item count information or - // - shows only a not very important information - // - if any progress is given don't show the item count info at all - const QString msg(m_statusBar->message()); - const bool updateStatusBarMsg = (msg.isEmpty() || - (msg == m_statusBar->defaultText()) || - (m_statusBar->type() == DolphinStatusBar::Information)) && - (m_statusBar->progress() == 100); - - const QString text(m_view->statusBarText()); - m_statusBar->setDefaultText(text); - - if (updateStatusBarMsg) { - m_statusBar->setMessage(text, DolphinStatusBar::Default); - } -} - void DolphinViewContainer::setNameFilter(const QString& nameFilter) { m_view->setNameFilter(nameFilter); - updateStatusBar(); + delayedStatusBarUpdate(); } void DolphinViewContainer::openContextMenu(const KFileItem& item, diff --git a/src/dolphinviewcontainer.h b/src/dolphinviewcontainer.h index db6ee69d5..1f8f1caf6 100644 --- a/src/dolphinviewcontainer.h +++ b/src/dolphinviewcontainer.h @@ -120,20 +120,28 @@ public slots: */ void showFilterBar(bool show); +signals: + /** + * Is emitted whenever the filter bar has changed its visibility state. + */ + void showFilterBarChanged(bool shown); + +private slots: /** * Updates the number of items (= number of files + number of * directories) in the statusbar. If files are selected, the number - * of selected files and the sum of the filesize is shown. + * of selected files and the sum of the filesize is shown. The update + * is done asynchronously, as getting the sum of the + * filesizes can be an expensive operation. */ - void updateStatusBar(); + void delayedStatusBarUpdate(); -signals: /** - * Is emitted whenever the filter bar has changed its visibility state. + * Is invoked by DolphinViewContainer::delayedStatusBarUpdate() and + * updates the status bar synchronously. */ - void showFilterBarChanged(bool shown); + void updateStatusBar(); -private slots: void updateProgress(int percent); /** @@ -256,7 +264,9 @@ private: DolphinView* m_view; FilterBar* m_filterBar; + DolphinStatusBar* m_statusBar; + QTimer* m_statusBarTimer; DolphinModel* m_dolphinModel; DolphinDirLister* m_dirLister; -- 2.47.3