Add a helpful message to the Search view when no query has been entered

This commit is contained in:
David Sansome 2012-06-10 19:00:51 +01:00
parent b669dd64fa
commit 6e41a20e61
8 changed files with 393 additions and 14 deletions

View File

@ -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

View File

@ -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)

View File

@ -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<SearchProvider*> 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) {

View File

@ -25,6 +25,7 @@
#include <QWidget>
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<SearchProviderStatusWidget*> provider_status_widgets_;
};
inline uint qHash(const GlobalSearchView::ContainerKey& key) {

View File

@ -6,13 +6,20 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>437</width>
<height>633</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">#help_text {
color: gray;
font-weight: bold;
margin: 1em 1em 4em 1em;
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
@ -28,16 +35,113 @@
</widget>
</item>
<item>
<widget class="AutoExpandingTreeView" name="results">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
<widget class="QStackedWidget" name="stack">
<property name="currentIndex">
<number>1</number>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<widget class="QWidget" name="results_page">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="AutoExpandingTreeView" name="results">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragOnly</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="help_page">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="help_frame">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="help_text">
<property name="text">
<string>Enter search terms above to find music on your computer and on the internet</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Clementine will find music in:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="enabled_list" native="true"/>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>But these sources are disabled:</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="disabled_list" native="true"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

View File

@ -0,0 +1,99 @@
/* 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 "globalsearch.h"
#include "searchprovider.h"
#include "searchproviderstatuswidget.h"
#include "ui_searchproviderstatuswidget.h"
#include "core/application.h"
#include "ui/iconloader.h"
#include <QMouseEvent>
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<QMouseEvent*>(event);
if (e->button() == Qt::LeftButton) {
if (!provider_->IsLoggedIn()) {
provider_->ShowConfig();
} else {
engine_->application()->OpenSettingsDialogAtPage(SettingsDialog::Page_GlobalSearch);
}
}
break;
}
default:
return false;
}
return true;
}

View File

@ -0,0 +1,42 @@
/* 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 SEARCHPROVIDERSTATUSWIDGET_H
#define SEARCHPROVIDERSTATUSWIDGET_H
#include <QWidget>
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

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SearchProviderStatusWidget</class>
<widget class="QWidget" name="SearchProviderStatusWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>464</width>
<height>110</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="icon">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="name">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="disabled_group" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="disabled_icon">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="disabled_reason">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>