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:
parent
b0688a2aa7
commit
35e34c6ca5
|
@ -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);
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue