Auto-expand tree items and lazy load album cover art

This commit is contained in:
David Sansome 2012-06-10 17:15:32 +01:00
parent 9c36cfa199
commit 41fab25569
8 changed files with 123 additions and 16 deletions

View File

@ -138,6 +138,7 @@ set(SOURCES
globalsearch/digitallyimportedsearchprovider.cpp
globalsearch/globalsearch.cpp
globalsearch/globalsearchitemdelegate.cpp
globalsearch/globalsearchsettingspage.cpp
globalsearch/globalsearchsortmodel.cpp
globalsearch/globalsearchview.cpp

View File

@ -0,0 +1,34 @@
/* This file is part of Clementine.
Copyright 2012, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "globalsearchitemdelegate.h"
#include "globalsearchview.h"
GlobalSearchItemDelegate::GlobalSearchItemDelegate(GlobalSearchView* view)
: LibraryItemDelegate(view),
view_(view)
{
}
void GlobalSearchItemDelegate::paint(
QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const {
// Tell the view we painted this item so it can lazy load some art.
const_cast<GlobalSearchView*>(view_)->LazyLoadArt(index);
LibraryItemDelegate::paint(painter, option, index);
}

View File

@ -0,0 +1,36 @@
/* This file is part of Clementine.
Copyright 2012, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLOBALSEARCHITEMDELEGATE_H
#define GLOBALSEARCHITEMDELEGATE_H
#include "library/libraryview.h"
class GlobalSearchView;
class GlobalSearchItemDelegate : public LibraryItemDelegate {
public:
GlobalSearchItemDelegate(GlobalSearchView* view);
void paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const;
private:
GlobalSearchView* view_;
};
#endif // GLOBALSEARCHITEMDELEGATE_H

View File

@ -16,6 +16,7 @@
*/
#include "globalsearch.h"
#include "globalsearchitemdelegate.h"
#include "globalsearchsortmodel.h"
#include "globalsearchview.h"
#include "searchprovider.h"
@ -24,7 +25,6 @@
#include "core/logging.h"
#include "core/mimedata.h"
#include "library/librarymodel.h"
#include "library/libraryview.h"
#include <QSortFilterProxyModel>
#include <QStandardItem>
@ -44,18 +44,24 @@ GlobalSearchView::GlobalSearchView(Application* app, QWidget* parent)
front_proxy_(new GlobalSearchSortModel(this)),
back_proxy_(new GlobalSearchSortModel(this)),
current_proxy_(front_proxy_),
swap_models_timer_(new QTimer(this))
swap_models_timer_(new QTimer(this)),
artist_icon_(":/icons/22x22/x-clementine-artist.png"),
album_icon_(":/icons/22x22/x-clementine-album.png")
{
ui_->setupUi(this);
connect(ui_->search, SIGNAL(textChanged(QString)), SLOT(TextEdited(QString)));
ui_->results->setItemDelegate(new LibraryItemDelegate(this));
ui_->results->setItemDelegate(new GlobalSearchItemDelegate(this));
group_by_[0] = LibraryModel::GroupBy_Artist;
group_by_[1] = LibraryModel::GroupBy_Album;
group_by_[2] = LibraryModel::GroupBy_None;
no_cover_icon_ = QPixmap(":nocover.png").scaled(
LibraryModel::kPrettyCoverSize, LibraryModel::kPrettyCoverSize,
Qt::KeepAspectRatio, Qt::SmoothTransformation);
// Set up the sorting proxy model
front_proxy_->setSourceModel(front_model_);
front_proxy_->setDynamicSortFilter(true);
@ -164,6 +170,7 @@ QStandardItem* GlobalSearchView::BuildContainers(
return parent;
}
QIcon icon;
QString display_text;
QString sort_text;
int year = 0;
@ -172,12 +179,14 @@ QStandardItem* GlobalSearchView::BuildContainers(
case LibraryModel::GroupBy_Artist:
display_text = LibraryModel::TextOrUnknown(s.artist());
sort_text = LibraryModel::SortTextForArtist(s.artist());
icon = artist_icon_;
break;
case LibraryModel::GroupBy_YearAlbum:
year = qMax(0, s.year());
display_text = LibraryModel::PrettyYearAlbum(year, s.album());
sort_text = LibraryModel::SortTextForYear(year) + s.album();
icon = album_icon_;
break;
case LibraryModel::GroupBy_Year:
@ -192,6 +201,7 @@ QStandardItem* GlobalSearchView::BuildContainers(
case LibraryModel::GroupBy_AlbumArtist: if (display_text.isNull()) display_text = s.effective_albumartist();
display_text = LibraryModel::TextOrUnknown(display_text);
sort_text = LibraryModel::SortTextForArtist(display_text);
icon = album_icon_;
break;
case LibraryModel::GroupBy_FileType:
@ -207,7 +217,7 @@ QStandardItem* GlobalSearchView::BuildContainers(
key->group_[level] = display_text;
QStandardItem* container = containers_[*key];
if (!container) {
container = new QStandardItem(display_text);
container = new QStandardItem(icon, display_text);
container->setData(key->provider_index_, Role_ProviderIndex);
container->setData(sort_text, LibraryModel::Role_SortText);
container->setData(group_by_[level], LibraryModel::Role_ContainerType);
@ -237,12 +247,30 @@ void GlobalSearchView::LazyLoadArt(const QModelIndex& proxy_index) {
return;
}
// Only load art for albums
const LibraryModel::GroupBy container_type = LibraryModel::GroupBy(
proxy_index.data(LibraryModel::Role_ContainerType).toInt());
if (container_type != LibraryModel::GroupBy_Album &&
container_type != LibraryModel::GroupBy_AlbumArtist &&
container_type != LibraryModel::GroupBy_YearAlbum) {
return;
}
// Mark the item as loading art
const QModelIndex source_index = front_proxy_->mapToSource(proxy_index);
front_model_->itemFromIndex(source_index)->setData(true, Role_LazyLoadingArt);
QStandardItem* item = front_model_->itemFromIndex(source_index);
item->setData(true, Role_LazyLoadingArt);
// Walk down the item's children until we find a track
while (item->rowCount()) {
item = item->child(0);
}
// Get the track's Result
const SearchProvider::Result result =
source_index.data(Role_Result).value<SearchProvider::Result>();
item->data(Role_Result).value<SearchProvider::Result>();
// Load the art.
int id = engine_->LoadArtAsync(result);
art_requests_[id] = source_index;
}

View File

@ -106,6 +106,10 @@ private:
QMap<int, QAction*> track_requests_;
QMap<int, QModelIndex> art_requests_;
QIcon artist_icon_;
QIcon album_icon_;
QPixmap no_cover_icon_;
};
inline uint qHash(const GlobalSearchView::ContainerKey& key) {

View File

@ -28,7 +28,7 @@
</widget>
</item>
<item>
<widget class="QTreeView" name="results">
<widget class="AutoExpandingTreeView" name="results">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
@ -48,6 +48,11 @@
<extends>QLineEdit</extends>
<header>widgets/lineedit.h</header>
</customwidget>
<customwidget>
<class>AutoExpandingTreeView</class>
<extends>QTreeView</extends>
<header>widgets/autoexpandingtreeview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@ -71,7 +71,6 @@ LibraryModel::LibraryModel(LibraryBackend* backend, Application* app,
total_song_count_(0),
artist_icon_(":/icons/22x22/x-clementine-artist.png"),
album_icon_(":/icons/22x22/x-clementine-album.png"),
no_cover_icon_(":nocover.png"),
playlists_dir_icon_(IconLoader::Load("folder-sound")),
playlist_icon_(":/icons/22x22/x-clementine-albums.png"),
init_task_id_(-1),
@ -92,7 +91,7 @@ LibraryModel::LibraryModel(LibraryBackend* backend, Application* app,
SIGNAL(ImageLoaded(quint64,QImage)),
SLOT(AlbumArtLoaded(quint64,QImage)));
no_cover_icon_pretty_ = QPixmap(":nocover.png").scaled(
no_cover_icon_ = QPixmap(":nocover.png").scaled(
kPrettyCoverSize, kPrettyCoverSize,
Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
@ -405,7 +404,7 @@ QString LibraryModel::AlbumIconPixmapCacheKey(const QModelIndex& index) const {
QVariant LibraryModel::AlbumIcon(const QModelIndex& index) {
LibraryItem* item = IndexToItem(index);
if (!item)
return no_cover_icon_pretty_;
return no_cover_icon_;
// Check the cache for a pixmap we already loaded.
const QString cache_key = AlbumIconPixmapCacheKey(index);
@ -416,7 +415,7 @@ QVariant LibraryModel::AlbumIcon(const QModelIndex& index) {
// Maybe we're loading a pixmap already?
if (pending_cache_keys_.contains(cache_key)) {
return no_cover_icon_pretty_;
return no_cover_icon_;
}
// No art is cached and we're not loading it already. Load art for the first
@ -429,7 +428,7 @@ QVariant LibraryModel::AlbumIcon(const QModelIndex& index) {
pending_cache_keys_.insert(cache_key);
}
return no_cover_icon_pretty_;
return no_cover_icon_;
}
void LibraryModel::AlbumArtLoaded(quint64 id, const QImage& image) {
@ -444,7 +443,7 @@ void LibraryModel::AlbumArtLoaded(quint64 id, const QImage& image) {
// Insert this image in the cache.
if (image.isNull()) {
// Set the no_cover image so we don't continually try to load art.
QPixmapCache::insert(cache_key, no_cover_icon_pretty_);
QPixmapCache::insert(cache_key, no_cover_icon_);
} else {
QPixmapCache::insert(cache_key, QPixmap::fromImage(image));
}

View File

@ -136,8 +136,9 @@ class LibraryModel : public SimpleTreeModel<LibraryItem> {
// Whether or not to use album cover art, if it exists, in the library view
void set_pretty_covers(bool use_pretty_covers);
bool use_pretty_covers() const { return use_pretty_covers_; }
//Whether or not to show letters heading in the library view
// Whether or not to show letters heading in the library view
void set_show_dividers(bool show_dividers);
// Utility functions for manipulating text
@ -259,8 +260,7 @@ class LibraryModel : public SimpleTreeModel<LibraryItem> {
QIcon album_icon_;
// used as a generic icon to show when no cover art is found,
// fixed to the same size as the artwork (32x32)
QPixmap no_cover_icon_pretty_;
QIcon no_cover_icon_;
QPixmap no_cover_icon_;
QIcon playlists_dir_icon_;
QIcon playlist_icon_;