Add save action from playlistlist tab, so we can save favorite playlists without opening them.

Remove unnecessary/duplicate actions from playlistlist tab.
This commit is contained in:
Arnaud Bienner 2013-05-23 20:09:35 +02:00
parent 7252beaab1
commit 253a8ffde4
9 changed files with 149 additions and 77 deletions

View File

@ -135,7 +135,7 @@ PlaylistBackend::Playlist PlaylistBackend::GetPlaylist(int id) {
return p;
}
QFuture<PlaylistItemPtr> PlaylistBackend::GetPlaylistItems(int playlist) {
QList<SqlRow> PlaylistBackend::GetPlaylistRows(int playlist) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
@ -157,7 +157,7 @@ QFuture<PlaylistItemPtr> PlaylistBackend::GetPlaylistItems(int playlist) {
q.bindValue(":playlist", playlist);
q.exec();
if (db_->CheckErrors(q))
return QFuture<PlaylistItemPtr>();
return QList<SqlRow>();
QList<SqlRow> rows;
@ -165,13 +165,30 @@ QFuture<PlaylistItemPtr> PlaylistBackend::GetPlaylistItems(int playlist) {
rows << SqlRow(q);
}
return rows;
}
QFuture<PlaylistItemPtr> PlaylistBackend::GetPlaylistItems(int playlist) {
QMutexLocker l(db_->Mutex());
QList<SqlRow> rows = GetPlaylistRows(playlist);
// it's probable that we'll have a few songs associated with the
// same CUE so we're caching results of parsing CUEs
boost::shared_ptr<NewSongFromQueryState> state_ptr(new NewSongFromQueryState());
return QtConcurrent::mapped(rows, boost::bind(&PlaylistBackend::NewPlaylistItemFromQuery, this, _1, state_ptr));
}
QFuture<Song> PlaylistBackend::GetPlaylistSongs(int playlist) {
QMutexLocker l(db_->Mutex());
QList<SqlRow> rows = GetPlaylistRows(playlist);
// it's probable that we'll have a few songs associated with the
// same CUE so we're caching results of parsing CUEs
boost::shared_ptr<NewSongFromQueryState> state_ptr(new NewSongFromQueryState());
return QtConcurrent::mapped(rows, boost::bind(&PlaylistBackend::NewSongFromQuery, this, _1, state_ptr));
}
PlaylistItemPtr PlaylistBackend::NewSongFromQuery(const SqlRow& row, boost::shared_ptr<NewSongFromQueryState> state) {
PlaylistItemPtr PlaylistBackend::NewPlaylistItemFromQuery(const SqlRow& row, boost::shared_ptr<NewSongFromQueryState> state) {
// The song tables get joined first, plus one each for the song ROWIDs
const int playlist_row = (Song::kColumns.count() + 1) * kSongTableJoins;
@ -184,6 +201,10 @@ PlaylistItemPtr PlaylistBackend::NewSongFromQuery(const SqlRow& row, boost::shar
}
}
Song PlaylistBackend::NewSongFromQuery(const SqlRow& row, boost::shared_ptr<NewSongFromQueryState> state) {
return NewPlaylistItemFromQuery(row, state)->Metadata();
}
// If song had a CUE and the CUE still exists, the metadata from it will
// be applied here.
PlaylistItemPtr PlaylistBackend::RestoreCueData(PlaylistItemPtr item, boost::shared_ptr<NewSongFromQueryState> state) {

View File

@ -66,6 +66,7 @@ class PlaylistBackend : public QObject {
PlaylistList GetAllFavoritePlaylists();
PlaylistBackend::Playlist GetPlaylist(int id);
PlaylistItemFuture GetPlaylistItems(int playlist);
QFuture<Song> GetPlaylistSongs(int playlist);
void SetPlaylistOrder(const QList<int>& ids);
void SetPlaylistUiPath(int id, const QString& path);
@ -87,7 +88,10 @@ class PlaylistBackend : public QObject {
QMutex mutex_;
};
PlaylistItemPtr NewSongFromQuery(const SqlRow& row, boost::shared_ptr<NewSongFromQueryState> state);
QList<SqlRow> GetPlaylistRows(int playlist);
Song NewSongFromQuery(const SqlRow& row, boost::shared_ptr<NewSongFromQueryState> state);
PlaylistItemPtr NewPlaylistItemFromQuery(const SqlRow& row, boost::shared_ptr<NewSongFromQueryState> state);
PlaylistItemPtr RestoreCueData(PlaylistItemPtr item, boost::shared_ptr<NewSongFromQueryState> state);
enum GetPlaylistsFlags {

View File

@ -295,40 +295,10 @@ void PlaylistContainer::LoadPlaylist() {
}
void PlaylistContainer::SavePlaylist(int id = -1) {
QString filename = settings_.value("last_save_playlist").toString();
// Use the tab name as the suggested name
QString suggested_name = ui_->tab_bar->tabText(ui_->tab_bar->currentIndex());
// We want to use the playlist tab name as a default filename, but in the
// same directory as the last saved file.
// Strip off filename components until we find something that's a folder
forever {
QFileInfo fileinfo(filename);
if (filename.isEmpty() || fileinfo.isDir())
break;
filename = filename.section('/', 0, -2);
}
// Use the home directory as a fallback in case the path is empty.
if (filename.isEmpty())
filename = QDir::homePath();
// Add the suggested filename based on the tab name
filename += "/" + ui_->tab_bar->tabText(ui_->tab_bar->currentIndex()) +
"." + manager_->parser()->default_extension();
QString default_filter = manager_->parser()->default_filter();
filename = QFileDialog::getSaveFileName(
this, tr("Save playlist"), filename,
manager_->parser()->filters(), &default_filter);
if (filename.isNull())
return;
settings_.setValue("last_save_playlist", filename);
manager_->Save(id == -1 ? manager_->current_id() : id, filename);
manager_->SaveWithUI(id, suggested_name);
}
void PlaylistContainer::GoToNextPlaylistTab() {

View File

@ -59,10 +59,8 @@ PlaylistListContainer::PlaylistListContainer(QWidget* parent)
ui_(new Ui_PlaylistListContainer),
menu_(NULL),
action_new_folder_(new QAction(this)),
action_new_playlist_(NULL),
action_remove_(new QAction(this)),
action_load_playlist_(NULL),
action_save_playlist_(NULL),
action_save_playlist_(new QAction(this)),
model_(new PlaylistListModel(this)),
proxy_(new PlaylistListSortFilterModel(this)),
loaded_icons_(false),
@ -73,12 +71,15 @@ PlaylistListContainer::PlaylistListContainer(QWidget* parent)
action_new_folder_->setText(tr("New folder"));
action_remove_->setText(tr("Delete"));
action_save_playlist_->setText(tr("Save playlist"));
ui_->new_folder->setDefaultAction(action_new_folder_);
ui_->remove->setDefaultAction(action_remove_);
ui_->save_playlist->setDefaultAction(action_save_playlist_);
connect(action_new_folder_, SIGNAL(triggered()), SLOT(NewFolderClicked()));
connect(action_remove_, SIGNAL(triggered()), SLOT(DeleteClicked()));
connect(action_save_playlist_, SIGNAL(triggered()), SLOT(SavePlaylist()));
connect(model_, SIGNAL(PlaylistPathChanged(int,QString)),
SLOT(PlaylistPathChanged(int,QString)));
@ -87,9 +88,8 @@ PlaylistListContainer::PlaylistListContainer(QWidget* parent)
proxy_->sort(0);
ui_->tree->setModel(proxy_);
connect(ui_->tree->selectionModel(),
SIGNAL(currentChanged(QModelIndex,QModelIndex)),
SLOT(ViewIndexSelected(QModelIndex)));
connect(ui_->tree, SIGNAL(doubleClicked(QModelIndex)),
SLOT(ItemDoubleClicked(QModelIndex)));
model_->invisibleRootItem()->setData(PlaylistListModel::Type_Folder, PlaylistListModel::Role_Type);
}
@ -107,6 +107,7 @@ void PlaylistListContainer::showEvent(QShowEvent* e) {
action_new_folder_->setIcon(IconLoader::Load("folder-new"));
action_remove_->setIcon(IconLoader::Load("edit-delete"));
action_save_playlist_->setIcon(IconLoader::Load("document-save"));
model_->SetIcons(IconLoader::Load("view-media-playlist"),
IconLoader::Load("folder"));
@ -165,19 +166,6 @@ void PlaylistListContainer::SetApplication(Application* app) {
}
}
void PlaylistListContainer::SetActions(QAction* new_playlist,
QAction* load_playlist,
QAction* save_playlist) {
// Set the actions on the buttons in the toolbar.
ui_->new_playlist->setDefaultAction(new_playlist);
ui_->load_playlist->setDefaultAction(load_playlist);
ui_->save_playlist->setDefaultAction(save_playlist);
action_new_playlist_ = new_playlist;
action_load_playlist_ = load_playlist;
action_save_playlist_ = save_playlist;
}
void PlaylistListContainer::NewFolderClicked() {
QString name = QInputDialog::getText(this, tr("New folder"),
tr("Enter the name of the folder"));
@ -228,6 +216,19 @@ void PlaylistListContainer::RemovePlaylist(int id) {
}
}
void PlaylistListContainer::SavePlaylist() {
const QModelIndex& current_index = proxy_->mapToSource(ui_->tree->currentIndex());
// Is it a playlist?
if (current_index.data(PlaylistListModel::Role_Type).toInt() ==
PlaylistListModel::Type_Playlist) {
const int playlist_id = current_index.data(PlaylistListModel::Role_PlaylistId).toInt();
QStandardItem* item = model_->PlaylistById(playlist_id);
QString playlist_name = item ? item->text() : tr("Playlist");
app_->playlist_manager()->SaveWithUI(playlist_id, playlist_name);
}
}
void PlaylistListContainer::PlaylistFavoriteStateChanged(int id, bool favorite) {
if (favorite) {
const QString& name = app_->playlist_manager()->GetPlaylistName(id);
@ -270,7 +271,7 @@ void PlaylistListContainer::PlaylistPathChanged(int id, const QString& new_path)
app_->playlist_manager()->playlist(id)->set_ui_path(new_path);
}
void PlaylistListContainer::ViewIndexSelected(const QModelIndex& proxy_index) {
void PlaylistListContainer::ItemDoubleClicked(const QModelIndex& proxy_index) {
const QModelIndex& index = proxy_->mapToSource(proxy_index);
// Is it a playlist?
@ -346,11 +347,9 @@ void PlaylistListContainer::RecursivelyFindPlaylists(
void PlaylistListContainer::contextMenuEvent(QContextMenuEvent* e) {
if (!menu_) {
menu_ = new QMenu(this);
menu_->addAction(action_new_playlist_);
menu_->addAction(action_new_folder_);
menu_->addAction(action_remove_);
menu_->addSeparator();
menu_->addAction(action_load_playlist_);
menu_->addAction(action_save_playlist_);
}
menu_->popup(e->globalPos());

View File

@ -39,8 +39,6 @@ public:
~PlaylistListContainer();
void SetApplication(Application* app);
void SetActions(QAction* new_playlist, QAction* load_playlist,
QAction* save_playlist);
protected:
void showEvent(QShowEvent* e);
@ -50,7 +48,7 @@ private slots:
// From the UI
void NewFolderClicked();
void DeleteClicked();
void ViewIndexSelected(const QModelIndex& index);
void ItemDoubleClicked(const QModelIndex& index);
// From the model
void PlaylistPathChanged(int id, const QString& new_path);
@ -60,6 +58,7 @@ private slots:
// Add playlist if favorite == true
void AddPlaylist(int id, const QString& name, bool favorite);
void RemovePlaylist(int id);
void SavePlaylist();
void PlaylistFavoriteStateChanged(int id, bool favorite);
void CurrentChanged(Playlist* new_playlist);
void ActiveChanged(Playlist* new_playlist);
@ -78,15 +77,12 @@ private:
void UpdateActiveIcon(int id, const QIcon& icon);
private:
Application* app_;
Ui_PlaylistListContainer* ui_;
QMenu* menu_;
QAction* action_new_folder_;
QAction* action_new_playlist_;
QAction* action_remove_;
QAction* action_load_playlist_;
QAction* action_save_playlist_;
PlaylistListModel* model_;

View File

@ -6,10 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<width>160</width>
<height>503</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
@ -22,6 +28,12 @@
</property>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
@ -36,9 +48,6 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="new_playlist"/>
</item>
<item>
<widget class="QToolButton" name="remove">
<property name="toolTip">
@ -54,10 +63,14 @@
</widget>
</item>
<item>
<widget class="QToolButton" name="load_playlist"/>
<widget class="QToolButton" name="save_playlist"/>
</item>
<item>
<widget class="QToolButton" name="save_playlist"/>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
@ -66,7 +79,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>319</width>
<width>70</width>
<height>20</height>
</size>
</property>
@ -77,6 +90,12 @@
</item>
<item>
<widget class="AutoExpandingTreeView" name="tree">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>

View File

@ -30,7 +30,10 @@
#include "playlistparsers/playlistparser.h"
#include "smartplaylists/generator.h"
#include <QFileDialog>
#include <QFileInfo>
#include <QFuture>
#include <QFutureWatcher>
#include <QtDebug>
using smart_playlists::GeneratorPtr;
@ -48,6 +51,8 @@ PlaylistManager::PlaylistManager(Application* app, QObject *parent)
connect(app_->player(), SIGNAL(Paused()), SLOT(SetActivePaused()));
connect(app_->player(), SIGNAL(Playing()), SLOT(SetActivePlaying()));
connect(app_->player(), SIGNAL(Stopped()), SLOT(SetActiveStopped()));
settings_.beginGroup(Playlist::kSettingsGroup);
}
PlaylistManager::~PlaylistManager() {
@ -179,11 +184,66 @@ void PlaylistManager::LoadFinished(bool success) {
}
void PlaylistManager::Save(int id, const QString& filename) {
Q_ASSERT(playlists_.contains(id));
if (playlists_.contains(id)) {
parser_->Save(playlist(id)->GetAllSongs(), filename);
} else {
// Playlist is not in the playlist manager: probably save action was triggered
// from the left side bar and the playlist isn't loaded.
QFuture<Song> future = playlist_backend_->GetPlaylistSongs(id);
QFutureWatcher<Song>* watcher = new QFutureWatcher<Song>(this);
watcher->setFuture(future);
parser_->Save(playlist(id)->GetAllSongs(), filename);
NewClosure(watcher, SIGNAL(finished()),
this, SLOT(ItemsLoadedForSavePlaylist(QFutureWatcher<Song>*, QString)), watcher, filename);
}
}
void PlaylistManager::ItemsLoadedForSavePlaylist(
QFutureWatcher<Song>* watcher,
const QString& filename) {
SongList song_list = watcher->future().results();
parser_->Save(song_list, filename);
}
void PlaylistManager::SaveWithUI(int id, const QString& suggested_filename) {
QString filename = settings_.value("last_save_playlist").toString();
// We want to use the playlist tab name as a default filename, but in the
// same directory as the last saved file.
// Strip off filename components until we find something that's a folder
forever {
QFileInfo fileinfo(filename);
if (filename.isEmpty() || fileinfo.isDir())
break;
filename = filename.section('/', 0, -2);
}
// Use the home directory as a fallback in case the path is empty.
if (filename.isEmpty())
filename = QDir::homePath();
// Add the suggested filename
filename += "/" + suggested_filename +
"." + parser()->default_extension();
QString default_filter = parser()->default_filter();
filename = QFileDialog::getSaveFileName(
NULL, tr("Save playlist"), filename,
parser()->filters(), &default_filter);
if (filename.isNull())
return;
settings_.setValue("last_save_playlist", filename);
Save(id == -1 ? current_id() : id, filename);
}
void PlaylistManager::Rename(int id, const QString& new_name) {
Q_ASSERT(playlists_.contains(id));

View File

@ -22,6 +22,7 @@
#include <QItemSelection>
#include <QMap>
#include <QObject>
#include <QSettings>
#include "core/song.h"
#include "smartplaylists/generator_fwd.h"
@ -176,6 +177,8 @@ public slots:
const QString& special_type = QString());
void Load(const QString& filename);
void Save(int id, const QString& filename);
// Display a file dialog to let user choose a file before saving the file
void SaveWithUI(int id, const QString& suggested_filename);
void Rename(int id, const QString& new_name);
void Favorite(int id, bool favorite);
void Delete(int id);
@ -216,6 +219,7 @@ private slots:
void UpdateSummaryText();
void SongsDiscovered(const SongList& songs);
void LoadFinished(bool success);
void ItemsLoadedForSavePlaylist(QFutureWatcher<Song>* watcher, const QString& filename);
private:
Playlist* AddPlaylist(int id, const QString& name, const QString& special_type,
@ -236,6 +240,8 @@ private:
PlaylistParser* parser_;
PlaylistContainer* playlist_container_;
QSettings settings_;
// key = id
QMap<int, Data> playlists_;

View File

@ -383,9 +383,6 @@ MainWindow::MainWindow(Application* app,
ui_->action_save_playlist,
ui_->action_next_playlist, /* These two actions aren't associated */
ui_->action_previous_playlist /* to a button but to the main window */ );
playlist_list_->SetActions(ui_->action_new_playlist,
ui_->action_load_playlist,
ui_->action_save_playlist);
#ifdef ENABLE_VISUALISATIONS