mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-31 03:27:40 +01:00
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:
parent
7252beaab1
commit
253a8ffde4
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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());
|
||||
|
@ -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_;
|
||||
|
@ -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>
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user