18
18
#include "playlistcontainer.h"
19
19
#include "playlistmanager.h"
20
#include "specialplaylisttype.h"
20
21
#include "ui_playlistcontainer.h"
22
#include "core/logging.h"
21
23
#include "playlistparsers/playlistparser.h"
22
24
#include "ui/iconloader.h"
25
#include "widgets/didyoumean.h"
23
26
#include "widgets/maclineedit.h"
28
#include <QFileDialog>
26
29
#include <QInputDialog>
31
#include <QMessageBox>
27
32
#include <QSettings>
33
#include <QSortFilterProxyModel>
28
34
#include <QTimeLine>
29
#include <QSortFilterProxyModel>
31
#include <QFileDialog>
32
#include <QMessageBox>
34
37
const char* PlaylistContainer::kSettingsGroup = "Playlist";
42
46
starting_up_(true),
43
47
tab_bar_visible_(false),
44
48
tab_bar_animation_(new QTimeLine(500, this)),
45
no_matches_label_(new QLabel(this))
49
no_matches_label_(NULL),
47
52
ui_->setupUi(this);
49
no_matches_label_->setText(tr("No matches found. Clear the search box to show the whole playlist again."));
54
no_matches_label_ = new QLabel(ui_->playlist);
50
55
no_matches_label_->setAlignment(Qt::AlignTop | Qt::AlignHCenter);
51
56
no_matches_label_->setAttribute(Qt::WA_TransparentForMouseEvents);
52
57
no_matches_label_->setWordWrap(true);
56
61
// Set the colour of the no matches label to the disabled text colour
57
62
QPalette no_matches_palette = no_matches_label_->palette();
58
no_matches_palette.setColor(
59
QPalette::Normal, QPalette::WindowText,
60
no_matches_palette.color(QPalette::Disabled, QPalette::Text));
63
const QColor no_matches_color = no_matches_palette.color(QPalette::Disabled, QPalette::Text);
64
no_matches_palette.setColor(QPalette::Normal, QPalette::WindowText, no_matches_color);
65
no_matches_palette.setColor(QPalette::Inactive, QPalette::WindowText, no_matches_color);
61
66
no_matches_label_->setPalette(no_matches_palette);
93
98
connect(ui_->playlist, SIGNAL(FocusOnFilterSignal(QKeyEvent*)), SLOT(FocusOnFilter(QKeyEvent*)));
94
99
ui_->filter->installEventFilter(this);
102
did_you_mean_ = new DidYouMean(filter_->widget(), this);
103
connect(did_you_mean_, SIGNAL(Accepted(QString)), SLOT(DidYouMeanAccepted(QString)));
98
106
PlaylistContainer::~PlaylistContainer() {
106
114
void PlaylistContainer::SetActions(
107
QAction* new_playlist, QAction* save_playlist, QAction* load_playlist) {
115
QAction* new_playlist, QAction* save_playlist, QAction* load_playlist,
116
QAction* next_playlist, QAction* previous_playlist) {
108
117
ui_->create_new->setDefaultAction(new_playlist);
109
118
ui_->save->setDefaultAction(save_playlist);
110
119
ui_->load->setDefaultAction(load_playlist);
114
123
connect(new_playlist, SIGNAL(triggered()), SLOT(NewPlaylist()));
115
124
connect(save_playlist, SIGNAL(triggered()), SLOT(SavePlaylist()));
116
125
connect(load_playlist, SIGNAL(triggered()), SLOT(LoadPlaylist()));
126
connect(next_playlist, SIGNAL(triggered()), SLOT(GoToNextPlaylistTab()));
127
connect(previous_playlist, SIGNAL(triggered()), SLOT(GoToPreviousPlaylistTab()));
119
130
void PlaylistContainer::SetManager(PlaylistManager *manager) {
144
155
disconnect(view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
145
156
this, SLOT(SelectionChanged()));
158
if (playlist_ && playlist_->proxy()) {
159
disconnect(playlist_->proxy(), SIGNAL(modelReset()),
160
this, SLOT(UpdateNoMatchesLabel()));
161
disconnect(playlist_->proxy(), SIGNAL(rowsInserted(QModelIndex,int,int)),
162
this, SLOT(UpdateNoMatchesLabel()));
163
disconnect(playlist_->proxy(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
164
this, SLOT(UpdateNoMatchesLabel()));
167
disconnect(playlist_, SIGNAL(modelReset()),
168
this, SLOT(UpdateNoMatchesLabel()));
169
disconnect(playlist_, SIGNAL(rowsInserted(QModelIndex,int,int)),
170
this, SLOT(UpdateNoMatchesLabel()));
171
disconnect(playlist_, SIGNAL(rowsRemoved(QModelIndex,int,int)),
172
this, SLOT(UpdateNoMatchesLabel()));
175
playlist_ = playlist;
149
178
playlist->IgnoreSorting(true);
161
190
filter_->set_text(playlist->proxy()->filterRegExp().pattern());
192
// Update the no matches label
193
connect(playlist_->proxy(), SIGNAL(modelReset()), SLOT(UpdateNoMatchesLabel()));
194
connect(playlist_->proxy(), SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
195
connect(playlist_->proxy(), SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
196
connect(playlist_, SIGNAL(modelReset()), SLOT(UpdateNoMatchesLabel()));
197
connect(playlist_, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
198
connect(playlist_, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
199
UpdateNoMatchesLabel();
163
201
// Ensure that tab is current
164
202
if (ui_->tab_bar->current_id() != manager_->current_id())
165
203
ui_->tab_bar->set_current_id(manager_->current_id());
178
216
ui_->redo->setDefaultAction(redo_);
180
218
emit UndoRedoActionsChanged(undo_, redo_);
220
did_you_mean()->hide();
222
// Implement special playlist behaviour
223
const SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
224
filter_->set_hint(type->search_hint_text(playlist));
183
227
void PlaylistContainer::ActivePlaying() {
195
239
void PlaylistContainer::UpdateActiveIcon(const QIcon& icon) {
196
240
// Unset all existing icons
197
241
for (int i=0 ; i<ui_->tab_bar->count() ; ++i) {
198
ui_->tab_bar->setTabIcon(i, QIcon());
242
// Get the default icon for this tab
243
const int id = ui_->tab_bar->tabData(i).toInt();
244
Playlist* playlist = manager_->playlist(id);
245
const SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
247
ui_->tab_bar->setTabIcon(i, type->icon(playlist));
206
255
void PlaylistContainer::PlaylistAdded(int id, const QString &name) {
207
int index = ui_->tab_bar->count();
208
ui_->tab_bar->InsertTab(id, index, name);
256
Playlist* playlist = manager_->playlist(id);
257
const SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
259
const int index = ui_->tab_bar->count();
260
const QIcon icon = type->icon(playlist);
261
ui_->tab_bar->InsertTab(id, index, name, icon);
210
263
// Are we startup up, should we select this tab?
211
264
if (starting_up_ && settings_.value("current_playlist", 1).toInt() == id) {
295
348
manager_->Save(id == -1 ? manager_->current_id() : id, filename);
351
void PlaylistContainer::GoToNextPlaylistTab() {
352
// Get the next tab' id
354
ui_->tab_bar->id_of((ui_->tab_bar->currentIndex()+1)%ui_->tab_bar->count());
355
// Switch to next tab
356
manager_->SetCurrentPlaylist(id_next);
359
void PlaylistContainer::GoToPreviousPlaylistTab() {
360
// Get the next tab' id
362
ui_->tab_bar->id_of((ui_->tab_bar->currentIndex()+ui_->tab_bar->count()-1)
363
% ui_->tab_bar->count());
364
// Switch to next tab
365
manager_->SetCurrentPlaylist(id_previous);
298
368
void PlaylistContainer::Save() {
299
369
if (starting_up_)
318
388
void PlaylistContainer::UpdateFilter() {
319
manager_->current()->proxy()->setFilterFixedString(filter_->text());
320
ui_->playlist->JumpToCurrentlyPlayingTrack();
322
bool no_matches = manager_->current()->proxy()->rowCount() == 0 &&
323
manager_->current()->rowCount() > 0;
389
Playlist* playlist = manager_->current();
390
SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
392
did_you_mean()->hide();
394
if (type->has_special_search_behaviour(playlist)) {
395
type->Search(filter_->text(), playlist);
397
manager_->current()->proxy()->setFilterFixedString(filter_->text());
398
ui_->playlist->JumpToCurrentlyPlayingTrack();
401
UpdateNoMatchesLabel();
404
void PlaylistContainer::UpdateNoMatchesLabel() {
405
Playlist* playlist = manager_->current();
406
SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
407
const QString empty_text = type->empty_playlist_text(playlist);
409
const bool has_rows = playlist->rowCount() != 0;
410
const bool has_results = playlist->proxy()->rowCount() != 0;
413
if (!empty_text.isEmpty() && !has_results) {
415
} else if (has_rows && !has_results) {
416
text = tr("No matches found. Clear the search box to show the whole playlist again.");
419
if (!text.isEmpty()) {
420
no_matches_label_->setText(text);
326
421
RepositionNoMatchesLabel(true);
327
no_matches_label_->setVisible(no_matches);
422
no_matches_label_->show();
424
no_matches_label_->hide();
330
428
void PlaylistContainer::resizeEvent(QResizeEvent* e) {
344
442
const int kBorder = 10;
346
QPoint pos = ui_->playlist->viewport()->mapTo(this, QPoint(kBorder, kBorder));
444
QPoint pos = ui_->playlist->viewport()->mapTo(ui_->playlist, QPoint(kBorder, kBorder));
347
445
QSize size = ui_->playlist->viewport()->size();
348
446
size.setWidth(size.width() - kBorder * 2);
349
447
size.setHeight(size.height() - kBorder * 2);
381
479
return QWidget::eventFilter(objectWatched, event);
384
QString PlaylistContainer::PromptForPlaylistName() {
385
return QInputDialog::getText(this, tr("New playlist"),
386
tr("Enter a name for the new playlist"),
387
QLineEdit::Normal, tr("Playlist"));
482
void PlaylistContainer::DidYouMeanAccepted(const QString& text) {
483
filter_->set_text(text);
485
Playlist* playlist = manager_->current();
486
SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type());
487
type->DidYouMeanClicked(text, playlist);