Hide the did you mean widget when leaving the search box, Don't lose the spotify tab icon when stopping playback, add a helpful label to the empty spotify search tab, remove the playlist CSS hook, fix double clicking the "Search spotify" item in the list

This commit is contained in:
David Sansome 2011-04-29 11:24:58 +00:00
parent b0688a2aa7
commit 35e34c6ca5
11 changed files with 114 additions and 37 deletions

View File

@ -19,19 +19,20 @@
#include "playlistmanager.h"
#include "specialplaylisttype.h"
#include "ui_playlistcontainer.h"
#include "core/logging.h"
#include "playlistparsers/playlistparser.h"
#include "ui/iconloader.h"
#include "widgets/didyoumean.h"
#include "widgets/maclineedit.h"
#include <QUndoStack>
#include <QInputDialog>
#include <QSettings>
#include <QTimeLine>
#include <QSortFilterProxyModel>
#include <QLabel>
#include <QFileDialog>
#include <QInputDialog>
#include <QLabel>
#include <QMessageBox>
#include <QSettings>
#include <QSortFilterProxyModel>
#include <QTimeLine>
#include <QUndoStack>
const char* PlaylistContainer::kSettingsGroup = "Playlist";
@ -41,15 +42,16 @@ PlaylistContainer::PlaylistContainer(QWidget *parent)
manager_(NULL),
undo_(NULL),
redo_(NULL),
playlist_(NULL),
starting_up_(true),
tab_bar_visible_(false),
tab_bar_animation_(new QTimeLine(500, this)),
no_matches_label_(new QLabel(this)),
no_matches_label_(NULL),
did_you_mean_(NULL)
{
ui_->setupUi(this);
no_matches_label_->setText(tr("No matches found. Clear the search box to show the whole playlist again."));
no_matches_label_ = new QLabel(ui_->playlist);
no_matches_label_->setAlignment(Qt::AlignTop | Qt::AlignHCenter);
no_matches_label_->setAttribute(Qt::WA_TransparentForMouseEvents);
no_matches_label_->setWordWrap(true);
@ -58,9 +60,9 @@ PlaylistContainer::PlaylistContainer(QWidget *parent)
// Set the colour of the no matches label to the disabled text colour
QPalette no_matches_palette = no_matches_label_->palette();
no_matches_palette.setColor(
QPalette::Normal, QPalette::WindowText,
no_matches_palette.color(QPalette::Disabled, QPalette::Text));
const QColor no_matches_color = no_matches_palette.color(QPalette::Disabled, QPalette::Text);
no_matches_palette.setColor(QPalette::Normal, QPalette::WindowText, no_matches_color);
no_matches_palette.setColor(QPalette::Inactive, QPalette::WindowText, no_matches_color);
no_matches_label_->setPalette(no_matches_palette);
// Make it bold
@ -153,6 +155,24 @@ void PlaylistContainer::SetViewModel(Playlist* playlist) {
disconnect(view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(SelectionChanged()));
}
if (playlist_ && playlist_->proxy()) {
disconnect(playlist_->proxy(), SIGNAL(modelReset()),
this, SLOT(UpdateNoMatchesLabel()));
disconnect(playlist_->proxy(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(UpdateNoMatchesLabel()));
disconnect(playlist_->proxy(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(UpdateNoMatchesLabel()));
}
if (playlist_) {
disconnect(playlist_, SIGNAL(modelReset()),
this, SLOT(UpdateNoMatchesLabel()));
disconnect(playlist_, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(UpdateNoMatchesLabel()));
disconnect(playlist_, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(UpdateNoMatchesLabel()));
}
playlist_ = playlist;
// Set the view
playlist->IgnoreSorting(true);
@ -169,6 +189,15 @@ void PlaylistContainer::SetViewModel(Playlist* playlist) {
// Update filter
filter_->set_text(playlist->proxy()->filterRegExp().pattern());
// Update the no matches label
connect(playlist_->proxy(), SIGNAL(modelReset()), SLOT(UpdateNoMatchesLabel()));
connect(playlist_->proxy(), SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
connect(playlist_->proxy(), SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
connect(playlist_, SIGNAL(modelReset()), SLOT(UpdateNoMatchesLabel()));
connect(playlist_, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
connect(playlist_, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
UpdateNoMatchesLabel();
// Ensure that tab is current
if (ui_->tab_bar->current_id() != manager_->current_id())
ui_->tab_bar->set_current_id(manager_->current_id());
@ -210,7 +239,12 @@ void PlaylistContainer::ActiveStopped() {
void PlaylistContainer::UpdateActiveIcon(const QIcon& icon) {
// Unset all existing icons
for (int i=0 ; i<ui_->tab_bar->count() ; ++i) {
ui_->tab_bar->setTabIcon(i, QIcon());
// Get the default icon for this tab
const int id = ui_->tab_bar->tabData(i).toInt();
Playlist* playlist = manager_->playlist(id);
const SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
ui_->tab_bar->setTabIcon(i, type->icon(playlist));
}
// Set our icon
@ -355,18 +389,39 @@ void PlaylistContainer::UpdateFilter() {
Playlist* playlist = manager_->current();
SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
did_you_mean()->hide();
if (type->has_special_search_behaviour(playlist)) {
type->Search(filter_->text(), playlist);
} else {
manager_->current()->proxy()->setFilterFixedString(filter_->text());
ui_->playlist->JumpToCurrentlyPlayingTrack();
}
const bool no_matches = manager_->current()->proxy()->rowCount() == 0 &&
manager_->current()->rowCount() > 0;
UpdateNoMatchesLabel();
}
if (no_matches)
RepositionNoMatchesLabel(true);
no_matches_label_->setVisible(no_matches);
void PlaylistContainer::UpdateNoMatchesLabel() {
Playlist* playlist = manager_->current();
SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
const QString empty_text = type->empty_playlist_text(playlist);
const bool has_rows = playlist->rowCount() != 0;
const bool has_results = playlist->proxy()->rowCount() != 0;
QString text;
if (!empty_text.isEmpty() && !has_results) {
text = empty_text;
} else if (has_rows && !has_results) {
text = tr("No matches found. Clear the search box to show the whole playlist again.");
}
if (!text.isEmpty()) {
no_matches_label_->setText(text);
RepositionNoMatchesLabel(true);
no_matches_label_->show();
} else {
no_matches_label_->hide();
}
}
@ -386,7 +441,7 @@ void PlaylistContainer::RepositionNoMatchesLabel(bool force) {
const int kBorder = 10;
QPoint pos = ui_->playlist->viewport()->mapTo(this, QPoint(kBorder, kBorder));
QPoint pos = ui_->playlist->viewport()->mapTo(ui_->playlist, QPoint(kBorder, kBorder));
QSize size = ui_->playlist->viewport()->size();
size.setWidth(size.width() - kBorder * 2);
size.setHeight(size.height() - kBorder * 2);

View File

@ -90,6 +90,7 @@ private slots:
void FocusOnFilter(QKeyEvent *event);
void DidYouMeanAccepted(const QString& text);
void UpdateNoMatchesLabel();
private:
void UpdateActiveIcon(const QIcon& icon);
@ -101,6 +102,7 @@ private:
PlaylistManager* manager_;
QAction* undo_;
QAction* redo_;
Playlist* playlist_;
QSettings settings_;
bool starting_up_;

View File

@ -33,7 +33,6 @@ public:
virtual QIcon icon(Playlist* playlist) const { return QIcon(); }
virtual QString search_hint_text(Playlist* playlist) const;
virtual QString empty_playlist_text(Playlist* playlist) const { return QString(); }
virtual QString playlist_view_css(Playlist* playlist) const { return QString(); }
virtual bool has_special_search_behaviour(Playlist* playlist) const { return false; }
virtual void Search(const QString& text, Playlist* playlist) {}

View File

@ -168,9 +168,11 @@ int RadioModel::rowCount(const QModelIndex& parent) const {
bool RadioModel::IsPlayable(const QModelIndex& index) const {
QVariant behaviour = index.data(Role_PlayBehaviour);
if (!behaviour.isValid() || behaviour.toInt() == PlayBehaviour_None)
if (!behaviour.isValid())
return false;
return true;
PlayBehaviour pb = PlayBehaviour(behaviour.toInt());
return (pb == PlayBehaviour_SingleItem || PlayBehaviour_UseSongLoader);
}
QStringList RadioModel::mimeTypes() const {
@ -178,6 +180,14 @@ QStringList RadioModel::mimeTypes() const {
}
QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const {
// Special case for when the user double clicked on a special item.
if (indexes.count() == 1 &&
indexes[0].data(Role_PlayBehaviour).toInt() ==
PlayBehaviour_DoubleClickAction) {
RadioModel::ServiceForIndex(indexes[0])->ItemDoubleClicked(itemFromIndex(indexes[0]));
return NULL;
}
QList<QUrl> urls;
QModelIndex last_valid_index;

View File

@ -95,6 +95,10 @@ public:
// behaviour occurs - the URL is just passed straight to gstreamer when
// the user starts playing.
PlayBehaviour_SingleItem,
// This item might not represent a song - the service's ItemDoubleClicked()
// slot will get called instead to do some custom action.
PlayBehaviour_DoubleClickAction,
};
// Needs to be static for RadioPlaylistItem::restore

View File

@ -45,8 +45,8 @@ public:
virtual QStandardItem* CreateRootItem() = 0;
virtual void LazyPopulate(QStandardItem* parent) = 0;
virtual void ShowContextMenu(const QModelIndex& index, const QPoint& global_pos) {
Q_UNUSED(index); Q_UNUSED(global_pos); }
virtual void ShowContextMenu(const QModelIndex& index, const QPoint& global_pos) {}
virtual void ItemDoubleClicked(QStandardItem* item) {}
virtual PlaylistItem::Options playlistitem_options() const { return PlaylistItem::Default; }

View File

@ -33,12 +33,7 @@ QString SpotifySearchPlaylistType::search_hint_text(Playlist* playlist) const {
}
QString SpotifySearchPlaylistType::empty_playlist_text(Playlist* playlist) const {
return QObject::tr("Start typing in the search box above to find music on Spotify");
}
QString SpotifySearchPlaylistType::playlist_view_css(Playlist* playlist) const {
// TODO
return QString();
return QObject::tr("Start typing in the search box above to find music on Spotify.");
}
bool SpotifySearchPlaylistType::has_special_search_behaviour(Playlist* playlist) const {

View File

@ -32,7 +32,6 @@ public:
virtual QIcon icon(Playlist* playlist) const;
virtual QString search_hint_text(Playlist* playlist) const;
virtual QString empty_playlist_text(Playlist* playlist) const;
virtual QString playlist_view_css(Playlist* playlist) const;
virtual bool has_special_search_behaviour(Playlist* playlist) const;
virtual void Search(const QString& text, Playlist* playlist);

View File

@ -170,10 +170,12 @@ void SpotifyService::PlaylistsUpdated(const protobuf::Playlists& response) {
}
// Create starred and inbox playlists if they're not here already
if (!search_results_) {
search_results_ = new QStandardItem(IconLoader::Load("edit-find"),
tr("Search Spotify (opens a new tab)"));
search_results_->setData(Type_SearchResults, RadioModel::Role_Type);
if (!search_) {
search_ = new QStandardItem(IconLoader::Load("edit-find"),
tr("Search Spotify (opens a new tab)"));
search_->setData(Type_SearchResults, RadioModel::Role_Type);
search_->setData(RadioModel::PlayBehaviour_DoubleClickAction,
RadioModel::Role_PlayBehaviour);
starred_ = new QStandardItem(QIcon(":/star-on.png"), tr("Starred"));
starred_->setData(Type_StarredPlaylist, RadioModel::Role_Type);
@ -183,7 +185,7 @@ void SpotifyService::PlaylistsUpdated(const protobuf::Playlists& response) {
inbox_->setData(Type_InboxPlaylist, RadioModel::Role_Type);
inbox_->setData(true, RadioModel::Role_CanLazyLoad);
root_->appendRow(search_results_);
root_->appendRow(search_);
root_->appendRow(starred_);
root_->appendRow(inbox_);
}
@ -381,3 +383,9 @@ void SpotifyService::OpenSearchTab() {
model()->player()->playlists()->New(tr("Search Spotify"), SongList(),
SpotifySearchPlaylistType::kName);
}
void SpotifyService::ItemDoubleClicked(QStandardItem* item) {
if (item == search_) {
OpenSearchTab();
}
}

View File

@ -42,6 +42,7 @@ public:
QStandardItem* CreateRootItem();
void LazyPopulate(QStandardItem* parent);
void ShowContextMenu(const QModelIndex& index, const QPoint& global_pos);
void ItemDoubleClicked(QStandardItem* item);
PlaylistItem::Options playlistitem_options() const;
void Login(const QString& username, const QString& password);
@ -85,7 +86,7 @@ private:
QProcess* blob_process_;
QStandardItem* root_;
QStandardItem* search_results_;
QStandardItem* search_;
QStandardItem* starred_;
QStandardItem* inbox_;
QList<QStandardItem*> playlists_;

View File

@ -52,6 +52,10 @@ bool DidYouMean::eventFilter(QObject* object, QEvent* event) {
}
break;
case QEvent::FocusOut:
hide();
break;
default:
break;
}
@ -90,7 +94,7 @@ void DidYouMean::paintEvent(QPaintEvent* ) {
kPadding,
rect().width() - kPadding,
rect().height() - kPadding);
const QString did_you_mean(tr("Did you mean "));
const QString did_you_mean(tr("Did you mean") + " ");
p.drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, did_you_mean);
text_rect.setLeft(text_rect.left() + fontMetrics().width(did_you_mean));