diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5dba787dc..28fb16564 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -147,6 +147,7 @@ set(SOURCES globalsearch/librarysearchprovider.cpp globalsearch/savedradiosearchprovider.cpp globalsearch/searchprovider.cpp + globalsearch/searchproviderstatuswidget.cpp globalsearch/simplesearchprovider.cpp globalsearch/somafmsearchprovider.cpp globalsearch/urlsearchprovider.cpp @@ -604,6 +605,7 @@ set(UI globalsearch/globalsearchsettingspage.ui globalsearch/globalsearchview.ui + globalsearch/searchproviderstatuswidget.ui internet/digitallyimportedsettingspage.ui internet/groovesharksettingspage.ui diff --git a/src/globalsearch/globalsearch.h b/src/globalsearch/globalsearch.h index a521fbf3d..247351ee5 100644 --- a/src/globalsearch/globalsearch.h +++ b/src/globalsearch/globalsearch.h @@ -38,6 +38,8 @@ public: static const char* kSettingsGroup; static const int kMaxResultsPerEmission; + Application* application() const { return app_; } + void AddProvider(SearchProvider* provider); // Try to change provider state. Returns false if we can't (e.g. we can't // enable a provider because it requires the user to be logged-in) diff --git a/src/globalsearch/globalsearchview.cpp b/src/globalsearch/globalsearchview.cpp index 35c54cc6a..1d146d9a1 100644 --- a/src/globalsearch/globalsearchview.cpp +++ b/src/globalsearch/globalsearchview.cpp @@ -20,6 +20,7 @@ #include "globalsearchsortmodel.h" #include "globalsearchview.h" #include "searchprovider.h" +#include "searchproviderstatuswidget.h" #include "ui_globalsearchview.h" #include "core/application.h" #include "core/logging.h" @@ -50,9 +51,23 @@ GlobalSearchView::GlobalSearchView(Application* app, QWidget* parent) { ui_->setupUi(this); + // Must be a queued connection to ensure the GlobalSearch handles it first. + connect(app_, SIGNAL(SettingsChanged()), SLOT(ReloadSettings()), Qt::QueuedConnection); + connect(ui_->search, SIGNAL(textChanged(QString)), SLOT(TextEdited(QString))); + // Set the appearance of the results list ui_->results->setItemDelegate(new GlobalSearchItemDelegate(this)); + ui_->results->setAttribute(Qt::WA_MacShowFocusRect, false); + ui_->results->setStyleSheet("QTreeView::item{padding-top:1px;}"); + + // Show the help page initially + ui_->stack->setCurrentWidget(ui_->help_page); + ui_->help_frame->setBackgroundRole(QPalette::Base); + QVBoxLayout* enabled_layout = new QVBoxLayout(ui_->enabled_list); + QVBoxLayout* disabled_layout = new QVBoxLayout(ui_->disabled_list); + enabled_layout->setContentsMargins(16, 0, 16, 6); + disabled_layout->setContentsMargins(16, 0, 16, 6); group_by_[0] = LibraryModel::GroupBy_Artist; group_by_[1] = LibraryModel::GroupBy_Album; @@ -84,15 +99,43 @@ GlobalSearchView::GlobalSearchView(Application* app, QWidget* parent) Qt::QueuedConnection); connect(engine_, SIGNAL(TracksLoaded(int,MimeData*)), SLOT(TracksLoaded(int,MimeData*)), Qt::QueuedConnection); + + ReloadSettings(); } GlobalSearchView::~GlobalSearchView() { delete ui_; } +namespace { + bool CompareProviderName(SearchProvider* left, SearchProvider* right) { + return left->name() < right->name(); + } +} + +void GlobalSearchView::ReloadSettings() { + qDeleteAll(provider_status_widgets_); + provider_status_widgets_.clear(); + + QList providers = engine_->providers(); + qSort(providers.begin(), providers.end(), CompareProviderName); + + foreach (SearchProvider* provider, providers) { + QWidget* parent = engine_->is_provider_usable(provider) + ? ui_->enabled_list + : ui_->disabled_list; + + SearchProviderStatusWidget* widget = + new SearchProviderStatusWidget(engine_, provider); + + parent->layout()->addWidget(widget); + provider_status_widgets_ << widget; + } +} + void GlobalSearchView::StartSearch(const QString& query) { ui_->search->set_text(query); - TextEdited(query.trimmed()); + TextEdited(query); // Swap models immediately swap_models_timer_->stop(); @@ -116,9 +159,9 @@ void GlobalSearchView::TextEdited(const QString& text) { // If text query is empty, don't start a new search if (trimmed.isEmpty()) { last_search_id_ = -1; - return; + } else { + last_search_id_ = engine_->SearchAsync(trimmed); } - last_search_id_ = engine_->SearchAsync(trimmed); } void GlobalSearchView::AddResults(int id, const SearchProvider::ResultList& results) { @@ -249,6 +292,12 @@ void GlobalSearchView::SwapModels() { qSwap(front_proxy_, back_proxy_); ui_->results->setModel(front_proxy_); + + if (ui_->search->text().trimmed().isEmpty()) { + ui_->stack->setCurrentWidget(ui_->help_page); + } else { + ui_->stack->setCurrentWidget(ui_->results_page); + } } void GlobalSearchView::LazyLoadArt(const QModelIndex& proxy_index) { diff --git a/src/globalsearch/globalsearchview.h b/src/globalsearch/globalsearchview.h index 0850f0931..05b48c088 100644 --- a/src/globalsearch/globalsearchview.h +++ b/src/globalsearch/globalsearchview.h @@ -25,6 +25,7 @@ #include class Application; +class SearchProviderStatusWidget; class Ui_GlobalSearchView; class QMimeData; @@ -65,6 +66,8 @@ signals: void OpenSettingsAtPage(SettingsDialog::Page page); private slots: + void ReloadSettings(); + void SwapModels(); void TextEdited(const QString& text); void AddResults(int id, const SearchProvider::ResultList& results); @@ -110,6 +113,8 @@ private: QIcon artist_icon_; QIcon album_icon_; QPixmap no_cover_icon_; + + QList provider_status_widgets_; }; inline uint qHash(const GlobalSearchView::ContainerKey& key) { diff --git a/src/globalsearch/globalsearchview.ui b/src/globalsearch/globalsearchview.ui index a6a2a8ba0..16f7e0859 100644 --- a/src/globalsearch/globalsearchview.ui +++ b/src/globalsearch/globalsearchview.ui @@ -6,13 +6,20 @@ 0 0 - 400 - 300 + 437 + 633 Form + + #help_text { + color: gray; + font-weight: bold; + margin: 1em 1em 4em 1em; +} + 0 @@ -28,16 +35,113 @@ - - - QAbstractItemView::NoEditTriggers + + + 1 - - true - - - false - + + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::DragOnly + + + QAbstractItemView::ExtendedSelection + + + true + + + false + + + + + + + + + 0 + + + + + true + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + Enter search terms above to find music on your computer and on the internet + + + Qt::AlignCenter + + + true + + + + + + + Clementine will find music in: + + + true + + + + + + + + + + But these sources are disabled: + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/globalsearch/searchproviderstatuswidget.cpp b/src/globalsearch/searchproviderstatuswidget.cpp new file mode 100644 index 000000000..ca8f79cee --- /dev/null +++ b/src/globalsearch/searchproviderstatuswidget.cpp @@ -0,0 +1,99 @@ +/* This file is part of Clementine. + Copyright 2012, 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 "globalsearch.h" +#include "searchprovider.h" +#include "searchproviderstatuswidget.h" +#include "ui_searchproviderstatuswidget.h" +#include "core/application.h" +#include "ui/iconloader.h" + +#include + +SearchProviderStatusWidget::SearchProviderStatusWidget(GlobalSearch* engine, + SearchProvider* provider, + QWidget* parent) + : QWidget(parent), + ui_(new Ui_SearchProviderStatusWidget), + engine_(engine), + provider_(provider) +{ + ui_->setupUi(this); + + ui_->icon->setPixmap(provider->icon().pixmap(16)); + ui_->name->setText(provider->name()); + + const bool enabled = engine->is_provider_enabled(provider); + const bool logged_in = provider->IsLoggedIn(); + + if (enabled && logged_in) { + ui_->disabled_group->hide(); + } else { + const QString disabled_text = tr("Disabled"); + const QString not_logged_in_text = tr("Not logged in"); + const int disabled_width = fontMetrics().width(" ") + qMax( + fontMetrics().width(disabled_text), + fontMetrics().width(not_logged_in_text)); + + ui_->disabled_reason->setMinimumWidth(disabled_width); + ui_->disabled_reason->setText(logged_in ? disabled_text : not_logged_in_text); + ui_->disabled_icon->setPixmap(IconLoader::Load("dialog-warning").pixmap(16)); + + ui_->disabled_reason->installEventFilter(this); + } +} + +SearchProviderStatusWidget::~SearchProviderStatusWidget() { + delete ui_; +} + +bool SearchProviderStatusWidget::eventFilter(QObject* object, QEvent* event) { + if (object != ui_->disabled_reason) { + return QWidget::eventFilter(object, event); + } + + QFont font(ui_->disabled_reason->font()); + + switch (event->type()) { + case QEvent::Enter: + font.setUnderline(true); + ui_->disabled_reason->setFont(font); + break; + + case QEvent::Leave: + font.setUnderline(false); + ui_->disabled_reason->setFont(font); + break; + + case QEvent::MouseButtonRelease: { + QMouseEvent* e = static_cast(event); + if (e->button() == Qt::LeftButton) { + if (!provider_->IsLoggedIn()) { + provider_->ShowConfig(); + } else { + engine_->application()->OpenSettingsDialogAtPage(SettingsDialog::Page_GlobalSearch); + } + } + break; + } + + default: + return false; + } + + return true; +} diff --git a/src/globalsearch/searchproviderstatuswidget.h b/src/globalsearch/searchproviderstatuswidget.h new file mode 100644 index 000000000..60d5504fc --- /dev/null +++ b/src/globalsearch/searchproviderstatuswidget.h @@ -0,0 +1,42 @@ +/* This file is part of Clementine. + Copyright 2012, 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 SEARCHPROVIDERSTATUSWIDGET_H +#define SEARCHPROVIDERSTATUSWIDGET_H + +#include + +class GlobalSearch; +class SearchProvider; +class Ui_SearchProviderStatusWidget; + +class SearchProviderStatusWidget : public QWidget { +public: + SearchProviderStatusWidget(GlobalSearch* engine, SearchProvider* provider, + QWidget* parent = 0); + ~SearchProviderStatusWidget(); + + bool eventFilter(QObject* object, QEvent* event); + +private: + Ui_SearchProviderStatusWidget* ui_; + + GlobalSearch* engine_; + SearchProvider* provider_; +}; + +#endif // SEARCHPROVIDERSTATUSWIDGET_H diff --git a/src/globalsearch/searchproviderstatuswidget.ui b/src/globalsearch/searchproviderstatuswidget.ui new file mode 100644 index 000000000..4065a0fec --- /dev/null +++ b/src/globalsearch/searchproviderstatuswidget.ui @@ -0,0 +1,76 @@ + + + SearchProviderStatusWidget + + + + 0 + 0 + 464 + 110 + + + + Form + + + + 0 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + PointingHandCursor + + + + + + + + + + +