From cd44c47f7ba505422bfb33e54c6bb615c98f5c35 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sun, 28 Aug 2011 22:20:22 +0100 Subject: [PATCH] Sort the results in the popup list, prevent the user from searching for short strings --- src/CMakeLists.txt | 2 + src/globalsearch/globalsearchitemdelegate.cpp | 185 ++++++++++++++ src/globalsearch/globalsearchitemdelegate.h | 49 ++++ src/globalsearch/globalsearchsortmodel.cpp | 68 ++++++ src/globalsearch/globalsearchsortmodel.h | 31 +++ src/globalsearch/globalsearchwidget.cpp | 225 ++++-------------- src/globalsearch/globalsearchwidget.h | 31 +-- src/globalsearch/searchprovider.h | 6 +- 8 files changed, 391 insertions(+), 206 deletions(-) create mode 100644 src/globalsearch/globalsearchitemdelegate.cpp create mode 100644 src/globalsearch/globalsearchitemdelegate.h create mode 100644 src/globalsearch/globalsearchsortmodel.cpp create mode 100644 src/globalsearch/globalsearchsortmodel.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 294a52021..c01a10559 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,8 @@ set(SOURCES engines/gstelementdeleter.cpp globalsearch/globalsearch.cpp + globalsearch/globalsearchitemdelegate.cpp + globalsearch/globalsearchsortmodel.cpp globalsearch/globalsearchwidget.cpp globalsearch/librarysearchprovider.cpp globalsearch/searchprovider.cpp diff --git a/src/globalsearch/globalsearchitemdelegate.cpp b/src/globalsearch/globalsearchitemdelegate.cpp new file mode 100644 index 000000000..876ae4d82 --- /dev/null +++ b/src/globalsearch/globalsearchitemdelegate.cpp @@ -0,0 +1,185 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + 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 . +*/ + +#include "globalsearchitemdelegate.h" +#include "globalsearchwidget.h" + +#include +#include + + +const int GlobalSearchItemDelegate::kHeight = SearchProvider::kArtHeight; +const int GlobalSearchItemDelegate::kMargin = 1; +const int GlobalSearchItemDelegate::kArtMargin = 6; +const int GlobalSearchItemDelegate::kWordPadding = 6; + +GlobalSearchItemDelegate::GlobalSearchItemDelegate(GlobalSearchWidget* widget) + : QStyledItemDelegate(widget), + widget_(widget) +{ + no_cover_ = ScaleAndPad(QImage(":nocover.png")); +} + +QPixmap GlobalSearchItemDelegate::ScaleAndPad(const QImage& image) { + if (image.isNull()) + return QPixmap(); + + if (image.size() == QSize(kHeight, kHeight)) + return QPixmap::fromImage(image); + + // Scale the image down + QImage copy; + copy = image.scaled(QSize(kHeight, kHeight), + Qt::KeepAspectRatio, Qt::SmoothTransformation); + + // Pad the image to kHeight x kHeight + QImage padded_image(kHeight, kHeight, QImage::Format_ARGB32); + padded_image.fill(0); + + QPainter p(&padded_image); + p.drawImage((kHeight - copy.width()) / 2, (kHeight - copy.height()) / 2, + copy); + p.end(); + + return QPixmap::fromImage(padded_image); +} + +QSize GlobalSearchItemDelegate::sizeHint(const QStyleOptionViewItem& option, + const QModelIndex& index) const { + QSize size = QStyledItemDelegate::sizeHint(option, index); + size.setHeight(kHeight + kMargin); + return size; +} + +void GlobalSearchItemDelegate::DrawAndShrink(QPainter* p, QRect* rect, + const QString& text) const { + QRect br; + p->drawText(*rect, Qt::TextSingleLine | Qt::AlignVCenter, text, &br); + rect->setLeft(br.right() + kWordPadding); +} + +void GlobalSearchItemDelegate::paint(QPainter* p, + const QStyleOptionViewItem& option, + const QModelIndex& index) const { + const SearchProvider::Result result = + index.data(GlobalSearchWidget::Role_Result).value(); + const Song& m = result.metadata_; + + widget_->LazyLoadArt(index); + + QFont bold_font = option.font; + bold_font.setBold(true); + + QColor pen = option.palette.color(QPalette::Text); + QColor light_pen = pen; + pen.setAlpha(200); + light_pen.setAlpha(128); + + // Draw the background + const QStyleOptionViewItemV3* vopt = qstyleoption_cast(&option); + const QWidget* widget = vopt->widget; + QStyle* style = widget->style() ? widget->style() : QApplication::style(); + style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, p, widget); + + // Draw the album art. This will already be the correct size. + const QRect rect = option.rect; + const QRect art_rect(rect.left() + kMargin, rect.top(), kHeight, kHeight); + + QPixmap art = index.data(Qt::DecorationRole).value(); + if (art.isNull()) + art = no_cover_; + + p->drawPixmap(art_rect, art); + + // Position text + QRect text_rect(art_rect.right() + kArtMargin, art_rect.top(), + rect.right() - art_rect.right() - kArtMargin, kHeight); + QRect text_rect_1(text_rect.adjusted(0, 0, 0, -kHeight/2)); + QRect text_rect_2(text_rect.adjusted(0, kHeight/2, 0, 0)); + + // The text we draw depends on the type of result. + switch (result.type_) { + case SearchProvider::Result::Type_Track: { + // Line 1 is Title + p->setFont(bold_font); + + // Title + p->setPen(pen); + DrawAndShrink(p, &text_rect_1, m.title()); + + // Line 2 is Artist - Album + p->setFont(option.font); + + // Artist + p->setPen(pen); + if (!m.artist().isEmpty()) { + DrawAndShrink(p, &text_rect_2, m.artist()); + } else if (!m.albumartist().isEmpty()) { + DrawAndShrink(p, &text_rect_2, m.albumartist()); + } + + if (!m.album().isEmpty()) { + // Dash + p->setPen(light_pen); + DrawAndShrink(p, &text_rect_2, " - "); + + // Album + p->setPen(pen); + DrawAndShrink(p, &text_rect_2, m.album()); + } + + break; + } + + case SearchProvider::Result::Type_Album: { + // Line 1 is Artist - Album + p->setFont(bold_font); + + // Artist + p->setPen(pen); + if (!m.albumartist().isEmpty()) + DrawAndShrink(p, &text_rect_1, m.albumartist()); + else if (m.is_compilation()) + DrawAndShrink(p, &text_rect_1, tr("Various Artists")); + else if (!m.artist().isEmpty()) + DrawAndShrink(p, &text_rect_1, m.artist()); + else + DrawAndShrink(p, &text_rect_1, tr("Unknown")); + + // Dash + p->setPen(light_pen); + DrawAndShrink(p, &text_rect_1, " - "); + + // Album + p->setPen(pen); + if (m.album().isEmpty()) + DrawAndShrink(p, &text_rect_1, tr("Unknown")); + else + DrawAndShrink(p, &text_rect_1, m.album()); + + // Line 2 is tracks + p->setFont(option.font); + + p->setPen(pen); + DrawAndShrink(p, &text_rect_2, QString::number(result.album_size_)); + + p->setPen(light_pen); + DrawAndShrink(p, &text_rect_2, tr(result.album_size_ == 1 ? "track" : "tracks")); + break; + } + } +} diff --git a/src/globalsearch/globalsearchitemdelegate.h b/src/globalsearch/globalsearchitemdelegate.h new file mode 100644 index 000000000..a07f5704f --- /dev/null +++ b/src/globalsearch/globalsearchitemdelegate.h @@ -0,0 +1,49 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + 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 . +*/ + +#ifndef GLOBALSEARCHITEMDELEGATE_H +#define GLOBALSEARCHITEMDELEGATE_H + +#include + +class GlobalSearchWidget; + + +class GlobalSearchItemDelegate : public QStyledItemDelegate { +public: + GlobalSearchItemDelegate(GlobalSearchWidget* widget); + + static const int kHeight; + static const int kMargin; + static const int kArtMargin; + static const int kWordPadding; + + static QPixmap ScaleAndPad(const QImage& image); + + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + +private: + void DrawAndShrink(QPainter* p, QRect* rect, const QString& text) const; + +private: + GlobalSearchWidget* widget_; + QPixmap no_cover_; +}; + +#endif // GLOBALSEARCHITEMDELEGATE_H diff --git a/src/globalsearch/globalsearchsortmodel.cpp b/src/globalsearch/globalsearchsortmodel.cpp new file mode 100644 index 000000000..92a549592 --- /dev/null +++ b/src/globalsearch/globalsearchsortmodel.cpp @@ -0,0 +1,68 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + 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 . +*/ + +#include "globalsearchwidget.h" +#include "globalsearchsortmodel.h" +#include "searchprovider.h" +#include "core/logging.h" + +GlobalSearchSortModel::GlobalSearchSortModel(QObject* parent) + : QSortFilterProxyModel(parent) +{ +} + +bool GlobalSearchSortModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { + const SearchProvider::Result r1 = left.data(GlobalSearchWidget::Role_Result) + .value(); + const SearchProvider::Result r2 = right.data(GlobalSearchWidget::Role_Result) + .value(); + + // Compare types first + if (r1.type_ < r2.type_) return true; + if (r1.type_ > r2.type_) return false; + + int ret = 0; + switch (r1.type_) { + case SearchProvider::Result::Type_Track: + ret = QString::localeAwareCompare(r1.metadata_.title(), r2.metadata_.title()); + if (ret < 0) return true; + if (ret > 0) return false; + + ret = QString::localeAwareCompare(r1.metadata_.artist(), r2.metadata_.artist()); + if (ret < 0) return true; + if (ret > 0) return false; + + ret = QString::localeAwareCompare(r1.metadata_.album(), r2.metadata_.album()); + if (ret < 0) return true; + if (ret > 0) return false; + + break; + + case SearchProvider::Result::Type_Album: + ret = QString::localeAwareCompare(r1.metadata_.artist(), r2.metadata_.artist()); + if (ret < 0) return true; + if (ret > 0) return false; + + ret = QString::localeAwareCompare(r1.metadata_.album(), r2.metadata_.album()); + if (ret < 0) return true; + if (ret > 0) return false; + + break; + } + + return false; +} diff --git a/src/globalsearch/globalsearchsortmodel.h b/src/globalsearch/globalsearchsortmodel.h new file mode 100644 index 000000000..b66de2f4e --- /dev/null +++ b/src/globalsearch/globalsearchsortmodel.h @@ -0,0 +1,31 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + 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 . +*/ + +#ifndef GLOBALSEARCHSORTMODEL_H +#define GLOBALSEARCHSORTMODEL_H + +#include + +class GlobalSearchSortModel : public QSortFilterProxyModel { +public: + GlobalSearchSortModel(QObject* parent = 0); + +protected: + bool lessThan(const QModelIndex& left, const QModelIndex& right) const; +}; + +#endif // GLOBALSEARCHSORTMODEL_H diff --git a/src/globalsearch/globalsearchwidget.cpp b/src/globalsearch/globalsearchwidget.cpp index 8bf9bad8d..c42164118 100644 --- a/src/globalsearch/globalsearchwidget.cpp +++ b/src/globalsearch/globalsearchwidget.cpp @@ -16,6 +16,8 @@ */ #include "globalsearch.h" +#include "globalsearchitemdelegate.h" +#include "globalsearchsortmodel.h" #include "globalsearchwidget.h" #include "librarysearchprovider.h" #include "ui_globalsearchwidget.h" @@ -25,177 +27,14 @@ #include #include +#include #include -const int GlobalSearchItemDelegate::kHeight = SearchProvider::kArtHeight; -const int GlobalSearchItemDelegate::kMargin = 1; -const int GlobalSearchItemDelegate::kArtMargin = 6; -const int GlobalSearchItemDelegate::kWordPadding = 6; + const int GlobalSearchWidget::kMinVisibleItems = 3; const int GlobalSearchWidget::kMaxVisibleItems = 12; -GlobalSearchItemDelegate::GlobalSearchItemDelegate(GlobalSearchWidget* widget) - : QStyledItemDelegate(widget), - widget_(widget) -{ - no_cover_ = ScaleAndPad(QImage(":nocover.png")); -} - -QPixmap GlobalSearchItemDelegate::ScaleAndPad(const QImage& image) { - if (image.isNull()) - return QPixmap(); - - if (image.size() == QSize(kHeight, kHeight)) - return QPixmap::fromImage(image); - - // Scale the image down - QImage copy; - copy = image.scaled(QSize(kHeight, kHeight), - Qt::KeepAspectRatio, Qt::SmoothTransformation); - - // Pad the image to kHeight x kHeight - QImage padded_image(kHeight, kHeight, QImage::Format_ARGB32); - padded_image.fill(0); - - QPainter p(&padded_image); - p.drawImage((kHeight - copy.width()) / 2, (kHeight - copy.height()) / 2, - copy); - p.end(); - - return QPixmap::fromImage(padded_image); -} - -QSize GlobalSearchItemDelegate::sizeHint(const QStyleOptionViewItem& option, - const QModelIndex& index) const { - QSize size = QStyledItemDelegate::sizeHint(option, index); - size.setHeight(kHeight + kMargin); - return size; -} - -void GlobalSearchItemDelegate::DrawAndShrink(QPainter* p, QRect* rect, - const QString& text) const { - QRect br; - p->drawText(*rect, Qt::TextSingleLine | Qt::AlignVCenter, text, &br); - rect->setLeft(br.right() + kWordPadding); -} - -void GlobalSearchItemDelegate::paint(QPainter* p, - const QStyleOptionViewItem& option, - const QModelIndex& index) const { - const SearchProvider::Result result = - index.data(GlobalSearchWidget::Role_Result).value(); - const Song& m = result.metadata_; - - widget_->LazyLoadArt(index); - - QFont bold_font = option.font; - bold_font.setBold(true); - - QColor pen = option.palette.color(QPalette::Text); - QColor light_pen = pen; - pen.setAlpha(200); - light_pen.setAlpha(128); - - // Draw the background - const QStyleOptionViewItemV3* vopt = qstyleoption_cast(&option); - const QWidget* widget = vopt->widget; - QStyle* style = widget->style() ? widget->style() : QApplication::style(); - style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, p, widget); - - // Draw the album art. This will already be the correct size. - const QRect rect = option.rect; - const QRect art_rect(rect.left() + kMargin, rect.top(), kHeight, kHeight); - - QPixmap art = index.data(Qt::DecorationRole).value(); - if (art.isNull()) - art = no_cover_; - - p->drawPixmap(art_rect, art); - - // Position text - QRect text_rect(art_rect.right() + kArtMargin, art_rect.top(), - rect.right() - art_rect.right() - kArtMargin, kHeight); - QRect text_rect_1(text_rect.adjusted(0, 0, 0, -kHeight/2)); - QRect text_rect_2(text_rect.adjusted(0, kHeight/2, 0, 0)); - - // The text we draw depends on the type of result. - switch (result.type_) { - case SearchProvider::Result::Type_Track: { - // Line 1 is Title - p->setFont(bold_font); - - // Title - p->setPen(pen); - DrawAndShrink(p, &text_rect_1, m.title()); - - // Line 2 is Artist - Album - p->setFont(option.font); - - // Artist - p->setPen(pen); - if (!m.artist().isEmpty()) { - DrawAndShrink(p, &text_rect_2, m.artist()); - } else if (!m.albumartist().isEmpty()) { - DrawAndShrink(p, &text_rect_2, m.albumartist()); - } - - if (!m.album().isEmpty()) { - // Dash - p->setPen(light_pen); - DrawAndShrink(p, &text_rect_2, " - "); - - // Album - p->setPen(pen); - DrawAndShrink(p, &text_rect_2, m.album()); - } - - break; - } - - case SearchProvider::Result::Type_Album: { - // Line 1 is Artist - Album - p->setFont(bold_font); - - // Artist - p->setPen(pen); - if (!m.albumartist().isEmpty()) - DrawAndShrink(p, &text_rect_1, m.albumartist()); - else if (m.is_compilation()) - DrawAndShrink(p, &text_rect_1, tr("Various Artists")); - else if (!m.artist().isEmpty()) - DrawAndShrink(p, &text_rect_1, m.artist()); - else - DrawAndShrink(p, &text_rect_1, tr("Unknown")); - - // Dash - p->setPen(light_pen); - DrawAndShrink(p, &text_rect_1, " - "); - - // Album - p->setPen(pen); - if (m.album().isEmpty()) - DrawAndShrink(p, &text_rect_1, tr("Unknown")); - else - DrawAndShrink(p, &text_rect_1, m.album()); - - // Line 2 is tracks - p->setFont(option.font); - - p->setPen(pen); - DrawAndShrink(p, &text_rect_2, QString::number(result.album_size_)); - - p->setPen(light_pen); - DrawAndShrink(p, &text_rect_2, tr(result.album_size_ == 1 ? "track" : "tracks")); - break; - } - - default: - break; - } -} - - GlobalSearchWidget::GlobalSearchWidget(QWidget* parent) : QWidget(parent), ui_(new Ui_GlobalSearchWidget), @@ -203,18 +42,23 @@ GlobalSearchWidget::GlobalSearchWidget(QWidget* parent) last_id_(0), clear_model_on_next_result_(false), model_(new QStandardItemModel(this)), + proxy_(new GlobalSearchSortModel(this)), view_(new QListView), eat_focus_out_(false), background_(":allthethings.png") { ui_->setupUi(this); + proxy_->setSourceModel(model_); + proxy_->setDynamicSortFilter(true); + proxy_->sort(0); + view_->setWindowFlags(Qt::Popup); view_->setFocusPolicy(Qt::NoFocus); view_->setFocusProxy(ui_->search); view_->installEventFilter(this); - view_->setModel(model_); + view_->setModel(proxy_); view_->setItemDelegate(new GlobalSearchItemDelegate(this)); view_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view_->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -222,6 +66,7 @@ GlobalSearchWidget::GlobalSearchWidget(QWidget* parent) connect(ui_->search, SIGNAL(textEdited(QString)), SLOT(TextEdited(QString))); connect(engine_, SIGNAL(ResultsAvailable(int,SearchProvider::ResultList)), SLOT(AddResults(int,SearchProvider::ResultList))); + connect(engine_, SIGNAL(SearchFinished(int)), SLOT(SearchFinished(int))); connect(engine_, SIGNAL(ArtLoaded(int,QImage)), SLOT(ArtLoaded(int,QImage))); } @@ -277,8 +122,33 @@ void GlobalSearchWidget::paintEvent(QPaintEvent* e) { } void GlobalSearchWidget::TextEdited(const QString& text) { + const QString trimmed_text = text.trimmed(); + + if (trimmed_text.length() < 3) { + Reset(); + RepositionPopup(); + return; + } + clear_model_on_next_result_ = true; - last_id_ = engine_->SearchAsync(text); + last_id_ = engine_->SearchAsync(trimmed_text); +} + +void GlobalSearchWidget::Reset() { + model_->clear(); + art_requests_.clear(); +} + +void GlobalSearchWidget::SearchFinished(int id) { + if (id != last_id_) + return; + + if (clear_model_on_next_result_) { + Reset(); + clear_model_on_next_result_ = true; + } + + RepositionPopup(); } void GlobalSearchWidget::AddResults(int id, const SearchProvider::ResultList& results) { @@ -286,8 +156,7 @@ void GlobalSearchWidget::AddResults(int id, const SearchProvider::ResultList& re return; if (clear_model_on_next_result_) { - model_->clear(); - art_requests_.clear(); + Reset(); clear_model_on_next_result_ = false; } @@ -350,7 +219,7 @@ bool GlobalSearchWidget::eventFilter(QObject* o, QEvent* e) { case Qt::Key_Up: if (!cur_index.isValid()) { - view_->setCurrentIndex(model_->index(model_->rowCount() - 1, 0)); + view_->setCurrentIndex(proxy_->index(proxy_->rowCount() - 1, 0)); return true; } else if (cur_index.row() == 0) { return true; @@ -359,9 +228,9 @@ bool GlobalSearchWidget::eventFilter(QObject* o, QEvent* e) { case Qt::Key_Down: if (!cur_index.isValid()) { - view_->setCurrentIndex(model_->index(0, 0)); + view_->setCurrentIndex(proxy_->index(0, 0)); return true; - } else if (cur_index.row() == model_->rowCount() - 1) { + } else if (cur_index.row() == proxy_->rowCount() - 1) { return true; } return false; @@ -430,18 +299,20 @@ bool GlobalSearchWidget::eventFilter(QObject* o, QEvent* e) { return false; } -void GlobalSearchWidget::LazyLoadArt(const QModelIndex& index) { - if (!index.isValid() || index.data(Role_LazyLoadingArt).isValid()) { +void GlobalSearchWidget::LazyLoadArt(const QModelIndex& proxy_index) { + if (!proxy_index.isValid() || proxy_index.data(Role_LazyLoadingArt).isValid()) { return; } - model_->itemFromIndex(index)->setData(true, Role_LazyLoadingArt); + const QModelIndex source_index = proxy_->mapToSource(proxy_index); + + model_->itemFromIndex(source_index)->setData(true, Role_LazyLoadingArt); const SearchProvider::Result result = - index.data(Role_Result).value(); + source_index.data(Role_Result).value(); int id = engine_->LoadArtAsync(result); - art_requests_[id] = index; + art_requests_[id] = source_index; } void GlobalSearchWidget::ArtLoaded(int id, const QImage& image) { diff --git a/src/globalsearch/globalsearchwidget.h b/src/globalsearch/globalsearchwidget.h index 1c54a3199..b62319a53 100644 --- a/src/globalsearch/globalsearchwidget.h +++ b/src/globalsearch/globalsearchwidget.h @@ -20,42 +20,18 @@ #include "searchprovider.h" -#include #include class GlobalSearch; -class GlobalSearchWidget; class LibraryBackendInterface; class Ui_GlobalSearchWidget; class QListView; +class QModelIndex; +class QSortFilterProxyModel; class QStandardItemModel; -class GlobalSearchItemDelegate : public QStyledItemDelegate { -public: - GlobalSearchItemDelegate(GlobalSearchWidget* widget); - - static const int kHeight; - static const int kMargin; - static const int kArtMargin; - static const int kWordPadding; - - static QPixmap ScaleAndPad(const QImage& image); - - QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; - void paint(QPainter* painter, const QStyleOptionViewItem& option, - const QModelIndex& index) const; - -private: - void DrawAndShrink(QPainter* p, QRect* rect, const QString& text) const; - -private: - GlobalSearchWidget* widget_; - QPixmap no_cover_; -}; - - class GlobalSearchWidget : public QWidget { Q_OBJECT @@ -85,11 +61,13 @@ protected: private slots: void TextEdited(const QString& text); + void SearchFinished(int id); void AddResults(int id, const SearchProvider::ResultList& results); void ArtLoaded(int id, const QImage& image); private: + void Reset(); void RepositionPopup(); private: @@ -102,6 +80,7 @@ private: QMap art_requests_; QStandardItemModel* model_; + QSortFilterProxyModel* proxy_; QListView* view_; bool eat_focus_out_; diff --git a/src/globalsearch/searchprovider.h b/src/globalsearch/searchprovider.h index 1f5abdb72..ec2a79883 100644 --- a/src/globalsearch/searchprovider.h +++ b/src/globalsearch/searchprovider.h @@ -36,10 +36,10 @@ public: Result(SearchProvider* provider = 0) : provider_(provider), album_size_(0) {} + // The order of types here is the order they'll appear in the UI. enum Type { - Type_Track, - Type_Album, - Type_Stream + Type_Track = 0, + Type_Album }; SearchProvider* provider_;