[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [amarok] /: Collection Browser: restore scroll location when the filter is cleared
From: Matěj_Laitl <matej () laitl ! cz>
Date: 2014-05-18 11:21:27
Message-ID: E1Wlz9j-0004y6-1x () scm ! kde ! org
[Download RAW message or body]
Git commit 12884560c4bec1f94422385fc798a0fd921ba8fc by Matěj Laitl.
Committed on 18/05/2014 at 09:34.
Pushed by laitl into branch 'master'.
Collection Browser: restore scroll location when the filter is cleared
FEATURES:
* Collection Browser scrolls back to its original position when the
filter is cleared.
FEATURE: 188074
FIXED-IN: 2.8.1
DIGEST: Amarok implements popular demand to restore scroll location
when collection filter is cleared
M +2 -0 ChangeLog
M +1 -1 src/browsers/CollectionTreeItemModel.cpp
M +25 -19 src/browsers/CollectionTreeItemModelBase.cpp
M +12 -0 src/browsers/CollectionTreeItemModelBase.h
M +75 -3 src/browsers/CollectionTreeView.cpp
http://commits.kde.org/amarok/12884560c4bec1f94422385fc798a0fd921ba8fc
diff --git a/ChangeLog b/ChangeLog
index a0365ae..387ee7f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,8 @@ Amarok ChangeLog
VERSION 2.8.1
FEATURES:
+ * Collection Browser scrolls back to its original position when the filter is \
cleared. + (BR 188074)
* Statistics synchronization between Amarok collections and
Amarok 1.4, Amarok 2.x, Apple iTunes, Banshee, Clementine, and
Rhythmbox track databases.
diff --git a/src/browsers/CollectionTreeItemModel.cpp \
b/src/browsers/CollectionTreeItemModel.cpp index 1ac4463..0110c2b 100644
--- a/src/browsers/CollectionTreeItemModel.cpp
+++ b/src/browsers/CollectionTreeItemModel.cpp
@@ -240,7 +240,7 @@ CollectionTreeItemModel::requestCollectionsExpansion()
{
for( int i = 0, count = m_rootItem->childCount(); i < count; i++ )
{
- emit expandIndex( createIndex( i, 0, m_rootItem->child( i ) ) );
+ emit expandIndex( itemIndex( m_rootItem->child( i ) ) );
}
}
diff --git a/src/browsers/CollectionTreeItemModelBase.cpp \
b/src/browsers/CollectionTreeItemModelBase.cpp index da35825..c08a197 100644
--- a/src/browsers/CollectionTreeItemModelBase.cpp
+++ b/src/browsers/CollectionTreeItemModelBase.cpp
@@ -367,10 +367,7 @@ CollectionTreeItemModelBase::parent(const QModelIndex & index) \
const
CollectionTreeItem *childItem = \
static_cast<CollectionTreeItem*>(index.internalPointer()); CollectionTreeItem \
*parentItem = childItem->parent();
- if ( (parentItem == m_rootItem) || !parentItem )
- return QModelIndex();
-
- return createIndex(parentItem->row(), 0, parentItem);
+ return itemIndex( parentItem );
}
int
@@ -490,6 +487,24 @@ CollectionTreeItemModelBase::ensureChildrenLoaded( \
CollectionTreeItem *item ) }
}
+CollectionTreeItem *
+CollectionTreeItemModelBase::treeItem( const QModelIndex &index ) const
+{
+ if( !index.isValid() || index.model() != this )
+ return 0;
+
+ return static_cast<CollectionTreeItem *>( index.internalPointer() );
+}
+
+QModelIndex
+CollectionTreeItemModelBase::itemIndex( CollectionTreeItem *item ) const
+{
+ if( !item || item == m_rootItem )
+ return QModelIndex();
+
+ return createIndex( item->row(), 0, item );
+}
+
void CollectionTreeItemModelBase::listForLevel(int level, Collections::QueryMaker * \
qm, CollectionTreeItem * parent) {
if( qm && parent )
@@ -639,7 +654,7 @@ CollectionTreeItemModelBase::queryDone()
//reset icon for this item
if( item && item != m_rootItem )
{
- emit dataChanged( createIndex(item->row(), 0, item), \
createIndex(item->row(), 0, item) ); + emit dataChanged( itemIndex( item ), \
itemIndex( item ) ); }
//stop timer if there are no more animations active
@@ -738,13 +753,9 @@ CollectionTreeItemModelBase::handleSpecialQueryResult( \
CollectionTreeItem::Type else if( type == CollectionTreeItem::NoLabel )
parent = m_noLabelsQueries.value( qm );
- QModelIndex parentIndex;
if( parent )
{
- if (parent == m_rootItem ) // will never happen in CollectionTreeItemModel
- parentIndex = QModelIndex();
- else
- parentIndex = createIndex( parent->row(), 0, parent );
+ QModelIndex parentIndex = itemIndex( parent );
//if the special query did not return a result we have to remove the
//the special node itself
@@ -803,7 +814,7 @@ CollectionTreeItemModelBase::handleSpecialQueryResult( \
CollectionTreeItem::Type
//only call populateChildren for the special node if we have not
//created it in this method call. The special node ctor takes care
//of that itself
- populateChildren( dataList, specialNode, createIndex( \
specialNode->row(), 0, specialNode ) ); + populateChildren( dataList, \
specialNode, itemIndex( specialNode ) ); }
//populate children will call setRequiresUpdate on vaNode
//but as the special query is based on specialNode's parent,
@@ -836,13 +847,8 @@ void
CollectionTreeItemModelBase::handleNormalQueryResult( Collections::QueryMaker *qm, \
const Meta::DataList &dataList ) {
CollectionTreeItem *parent = m_childQueries.value( qm );
- QModelIndex parentIndex;
if( parent ) {
- if( parent == m_rootItem ) // will never happen in CollectionTreeItemModel, \
but will happen in Single!
- parentIndex = QModelIndex();
- else
- parentIndex = createIndex( parent->row(), 0, parent );
-
+ QModelIndex parentIndex = itemIndex( parent );
populateChildren( dataList, parent, parentIndex );
if ( parent->isDataItem() )
@@ -1065,7 +1071,7 @@ void CollectionTreeItemModelBase::loadingAnimationTick()
{
if( item == m_rootItem )
continue;
- emit dataChanged ( createIndex(item->row(), 0, item), \
createIndex(item->row(), 0, item) ); + emit dataChanged( itemIndex( item ), \
itemIndex( item ) ); }
}
@@ -1093,7 +1099,7 @@ CollectionTreeItemModelBase::slotFilter( bool autoExpand )
{
CollectionTreeItem *expandedItem = m_collections.value( \
expanded->collectionId() ).second; if( expandedItem )
- emit expandIndex( createIndex( expandedItem->row(), 0, expandedItem ) );
+ emit expandIndex( itemIndex( expandedItem ) );
}
}
diff --git a/src/browsers/CollectionTreeItemModelBase.h \
b/src/browsers/CollectionTreeItemModelBase.h index 8517755..804d501 100644
--- a/src/browsers/CollectionTreeItemModelBase.h
+++ b/src/browsers/CollectionTreeItemModelBase.h
@@ -96,6 +96,18 @@ class AMAROK_EXPORT CollectionTreeItemModelBase : public \
QAbstractItemModel
void ensureChildrenLoaded( CollectionTreeItem *item );
+ /**
+ * Get a pointer to colleciton tree item given its index. It is not safe to
+ * cache this pointer unless QWeakPointer is used.
+ */
+ CollectionTreeItem *treeItem( const QModelIndex &index ) const;
+
+ /**
+ * Get (create) index for a collection tree item. The caller must ensure \
this + * item is in this model. Invalid model index is returned on null or \
root item. + */
+ QModelIndex itemIndex( CollectionTreeItem *item ) const;
+
signals:
void expandIndex( const QModelIndex &index );
void allQueriesFinished( bool autoExpand );
diff --git a/src/browsers/CollectionTreeView.cpp \
b/src/browsers/CollectionTreeView.cpp index 10b5cbc..816d2e1 100644
--- a/src/browsers/CollectionTreeView.cpp
+++ b/src/browsers/CollectionTreeView.cpp
@@ -56,9 +56,60 @@
#include <QHash>
#include <QMouseEvent>
#include <QSortFilterProxyModel>
+#include <QScrollBar>
using namespace Collections;
+/**
+ * RAII class to perform restoring of the scroll position once all queries are
+ * finished. DelayedScroller auto-deletes itself once its job is over (ot if it \
finds + * it is useless).
+ */
+class DelayedScroller : public QObject
+{
+ Q_OBJECT
+
+ public:
+ DelayedScroller( CollectionTreeView *treeView,
+ CollectionTreeItemModelBase *treeModel,
+ const QModelIndex &treeModelScrollToIndex, int topOffset )
+ : QObject( treeView )
+ , m_treeView( treeView )
+ , m_treeModel( treeModel )
+ , m_topOffset( topOffset )
+ {
+ connect( treeModel, SIGNAL(destroyed(QObject*)), SLOT(deleteLater()) );
+ connect( treeModel, SIGNAL(allQueriesFinished(bool)), SLOT(slotScroll()) \
); +
+ m_scrollToItem = m_treeModel->treeItem( treeModelScrollToIndex );
+ if( m_scrollToItem )
+ connect( m_scrollToItem, SIGNAL(destroyed(QObject*)), \
SLOT(deleteLater()) ); + else
+ deleteLater(); // nothing to do
+ }
+
+ private slots:
+ void slotScroll()
+ {
+ deleteLater();
+ QModelIndex idx = m_treeModel->itemIndex( m_scrollToItem );
+ QSortFilterProxyModel *filterModel = m_treeView->filterModel();
+ idx = filterModel ? filterModel->mapFromSource( idx ) : QModelIndex();
+ QScrollBar *scrollBar = m_treeView->verticalScrollBar();
+ if( !idx.isValid() || !scrollBar )
+ return;
+
+ int newTopOffset = m_treeView->visualRect( idx ).top();
+ scrollBar->setValue( scrollBar->value() + (newTopOffset - m_topOffset) \
); + }
+
+ private:
+ CollectionTreeView *m_treeView;
+ CollectionTreeItemModelBase *m_treeModel;
+ CollectionTreeItem *m_scrollToItem;
+ int m_topOffset;
+};
+
CollectionTreeView::CollectionTreeView( QWidget *parent)
: Amarok::PrettyTreeView( parent )
, m_filterModel( 0 )
@@ -900,8 +951,28 @@ CollectionTreeView::editTracks( const QSet<CollectionTreeItem *> \
&items ) const void
CollectionTreeView::slotSetFilter( const QString &filter )
{
- if( m_treeModel && m_treeModel->currentFilter() != filter )
- m_treeModel->setCurrentFilter( filter );
+ QString currentFilter = m_treeModel ? m_treeModel->currentFilter() : QString();
+ if( !m_filterModel || !m_treeModel || filter == currentFilter )
+ return;
+
+ // special case: transitioning from non-empty to empty buffer
+ // -> trigger later restoring of the scroll position
+ if( filter.isEmpty() ) // currentFilter must not be empty then (see earlier \
check) + {
+ // take first item, descending to leaf ones if expanded. There may be better
+ // ways to determine what item should stay "fixed".
+ QModelIndex scrollToIndex = m_filterModel->index( 0, 0 );
+ while( isExpanded( scrollToIndex ) && m_filterModel->rowCount( scrollToIndex \
) > 0 ) + scrollToIndex = scrollToIndex.child( 0, 0 );
+ int topOffset = visualRect( scrollToIndex ).top();
+
+ QModelIndex bottomIndex = m_filterModel->mapToSource( scrollToIndex );
+ // if we have somewhere to scroll to after filter is cleared...
+ if( bottomIndex.isValid() )
+ // auto-destroys itself
+ new DelayedScroller( this, m_treeModel, bottomIndex, topOffset );
+ }
+ m_treeModel->setCurrentFilter( filter );
}
void
@@ -1329,4 +1400,5 @@ CollectionTreeView::createMetaQueryFromItems( const \
QSet<CollectionTreeItem *> & return new Collections::MetaQueryMaker( queryMakers );
}
-#include "CollectionTreeView.moc"
+#include "CollectionTreeView.moc" // Q_OBJECTs defined in CollectionTreeView.cpp
+#include "moc_CollectionTreeView.cpp" // Q_OBJECTs defined in CollectionTreeView.h
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic