diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e544b716b..ca745ec4b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -186,6 +186,7 @@ set(SOURCES dialogs/deleteconfirmationdialog.cpp dialogs/lastfmimportdialog.cpp dialogs/snapdialog.cpp + dialogs/saveplaylistsdialog.cpp widgets/autoexpandingtreeview.cpp widgets/busyindicator.cpp @@ -417,6 +418,7 @@ set(HEADERS dialogs/deleteconfirmationdialog.h dialogs/lastfmimportdialog.h dialogs/snapdialog.h + dialogs/saveplaylistsdialog.h widgets/autoexpandingtreeview.h widgets/busyindicator.h @@ -542,6 +544,7 @@ set(UI dialogs/userpassdialog.ui dialogs/lastfmimportdialog.ui dialogs/snapdialog.ui + dialogs/saveplaylistsdialog.ui widgets/trackslider.ui widgets/fileview.ui diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index 2b59dd7c7..8e2b9bb94 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -460,6 +460,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr tray_ic ui_->action_remove_duplicates->setIcon(IconLoader::Load("list-remove")); ui_->action_remove_unavailable->setIcon(IconLoader::Load("list-remove")); ui_->action_remove_from_playlist->setIcon(IconLoader::Load("list-remove")); + ui_->action_save_all_playlists->setIcon(IconLoader::Load("document-save-all")); // Configure @@ -565,7 +566,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr tray_ic ui_->button_scrobble->setDefaultAction(ui_->action_toggle_scrobbling); ui_->button_love->setDefaultAction(ui_->action_love); - ui_->playlist->SetActions(ui_->action_new_playlist, ui_->action_load_playlist, ui_->action_save_playlist, ui_->action_clear_playlist, ui_->action_next_playlist, /* These two actions aren't associated */ ui_->action_previous_playlist /* to a button but to the main window */); + ui_->playlist->SetActions(ui_->action_new_playlist, ui_->action_load_playlist, ui_->action_save_playlist, ui_->action_clear_playlist, ui_->action_next_playlist, /* These two actions aren't associated */ ui_->action_previous_playlist /* to a button but to the main window */, ui_->action_save_all_playlists); // Add the shuffle and repeat action groups to the menu ui_->action_shuffle_mode->setMenu(ui_->playlist_sequence->shuffle_menu()); ui_->action_repeat_mode->setMenu(ui_->playlist_sequence->repeat_menu()); diff --git a/src/core/mainwindow.ui b/src/core/mainwindow.ui index 95d82ef86..cb7374c63 100644 --- a/src/core/mainwindow.ui +++ b/src/core/mainwindow.ui @@ -448,7 +448,7 @@ 0 0 1131 - 26 + 23 @@ -483,6 +483,7 @@ + @@ -747,6 +748,11 @@ Ctrl+Shift+O + + + &Save all playlists... + + Go to next playlist tab @@ -897,7 +903,6 @@ - diff --git a/src/dialogs/saveplaylistsdialog.cpp b/src/dialogs/saveplaylistsdialog.cpp new file mode 100644 index 000000000..c2bdd96a0 --- /dev/null +++ b/src/dialogs/saveplaylistsdialog.cpp @@ -0,0 +1,90 @@ +/* + * Strawberry Music Player + * Copyright 2022, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "saveplaylistsdialog.h" +#include "ui_saveplaylistsdialog.h" + +#include "playlist/playlist.h" + +SavePlaylistsDialog::SavePlaylistsDialog(const QStringList &types, const QString &default_extension) : ui_(new Ui_SavePlaylistsDialog) { + + ui_->setupUi(this); + + QSettings s; + s.beginGroup(Playlist::kSettingsGroup); + QString last_save_path = s.value("last_save_all_path", QDir::homePath()).toString(); + QString last_save_extension = s.value("last_save_all_extension", default_extension).toString(); + s.endGroup(); + + ui_->lineedit_path->setText(last_save_path); + ui_->combobox_type->addItems(types); + + int index = ui_->combobox_type->findText(last_save_extension); + if (index >= 0) { + ui_->combobox_type->setCurrentIndex(index); + } + + QObject::connect(ui_->button_path, &QPushButton::clicked, this, &SavePlaylistsDialog::SelectPath); + +} + +SavePlaylistsDialog::~SavePlaylistsDialog() { + delete ui_; +} + +void SavePlaylistsDialog::SelectPath() { + + const QString path = QFileDialog::getExistingDirectory(nullptr, tr("Select directory for the playlists"), ui_->lineedit_path->text(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if (path.isEmpty()) return; + + ui_->lineedit_path->setText(path); + +} + +void SavePlaylistsDialog::accept() { + + const QString path = ui_->lineedit_path->text(); + if (path.isEmpty()) { + return; + } + + if (!QDir().exists(path)) { + QMessageBox(QMessageBox::Warning, tr("Directory does not exist."), tr("Directory does not exist."), QMessageBox::Ok).exec(); + return; + } + + QSettings s; + s.beginGroup(Playlist::kSettingsGroup); + s.setValue("last_save_all_path", path); + s.setValue("last_save_all_extension", ui_->combobox_type->currentText()); + s.endGroup(); + + QDialog::accept(); + +} diff --git a/src/dialogs/saveplaylistsdialog.h b/src/dialogs/saveplaylistsdialog.h new file mode 100644 index 000000000..fb8f3ecba --- /dev/null +++ b/src/dialogs/saveplaylistsdialog.h @@ -0,0 +1,50 @@ +/* + * Strawberry Music Player + * Copyright 2022, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef SAVEPLAYLISTSDIALOG_H +#define SAVEPLAYLISTSDIALOG_H + +#include +#include +#include +#include + +#include "ui_saveplaylistsdialog.h" + +class SavePlaylistsDialog : public QDialog { + Q_OBJECT + + public: + explicit SavePlaylistsDialog(const QStringList &types, const QString &default_extension); + ~SavePlaylistsDialog(); + + QString path() const { return ui_->lineedit_path->text(); } + QString extension() const { return ui_->combobox_type->currentText(); }; + + protected: + void accept() override; + + private slots: + void SelectPath(); + + private: + Ui_SavePlaylistsDialog *ui_; +}; + +#endif // SAVEPLAYLISTSDIALOG_H diff --git a/src/dialogs/saveplaylistsdialog.ui b/src/dialogs/saveplaylistsdialog.ui new file mode 100644 index 000000000..0e9164371 --- /dev/null +++ b/src/dialogs/saveplaylistsdialog.ui @@ -0,0 +1,145 @@ + + + SavePlaylistsDialog + + + + 0 + 0 + 440 + 140 + + + + Select directory for saving playlists + + + + :/icons/128x128/strawberry.png:/icons/128x128/strawberry.png + + + + + + + + + + + + 0 + 0 + + + + + 40 + 16777215 + + + + + + + + :/icons/64x64/folder.png:/icons/64x64/folder.png + + + + + + + + + + + Type + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + lineedit_path + button_path + combobox_type + + + + + + + buttonBox + accepted() + SavePlaylistsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SavePlaylistsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/playlist/playlistcontainer.cpp b/src/playlist/playlistcontainer.cpp index c1cc95397..1a3c0c354 100644 --- a/src/playlist/playlistcontainer.cpp +++ b/src/playlist/playlistcontainer.cpp @@ -132,7 +132,7 @@ PlaylistContainer::~PlaylistContainer() { delete ui_; } PlaylistView *PlaylistContainer::view() const { return ui_->playlist; } -void PlaylistContainer::SetActions(QAction *new_playlist, QAction *load_playlist, QAction *save_playlist, QAction *clear_playlist, QAction *next_playlist, QAction *previous_playlist) { +void PlaylistContainer::SetActions(QAction *new_playlist, QAction *load_playlist, QAction *save_playlist, QAction *clear_playlist, QAction *next_playlist, QAction *previous_playlist, QAction *save_all_playlists) { ui_->create_new->setDefaultAction(new_playlist); ui_->load->setDefaultAction(load_playlist); @@ -148,6 +148,7 @@ void PlaylistContainer::SetActions(QAction *new_playlist, QAction *load_playlist QObject::connect(next_playlist, &QAction::triggered, this, &PlaylistContainer::GoToNextPlaylistTab); QObject::connect(previous_playlist, &QAction::triggered, this, &PlaylistContainer::GoToPreviousPlaylistTab); QObject::connect(clear_playlist, &QAction::triggered, this, &PlaylistContainer::ClearPlaylist); + QObject::connect(save_all_playlists, &QAction::triggered, manager_, &PlaylistManager::SaveAllPlaylists); } diff --git a/src/playlist/playlistcontainer.h b/src/playlist/playlistcontainer.h index 23dbb6092..eacab4391 100644 --- a/src/playlist/playlistcontainer.h +++ b/src/playlist/playlistcontainer.h @@ -53,7 +53,7 @@ class PlaylistContainer : public QWidget { static const char *kSettingsGroup; - void SetActions(QAction *new_playlist, QAction *load_playlist, QAction *save_playlist, QAction *clear_playlist, QAction *next_playlist, QAction *previous_playlist); + void SetActions(QAction *new_playlist, QAction *load_playlist, QAction *save_playlist, QAction *clear_playlist, QAction *next_playlist, QAction *previous_playlist, QAction *save_all_playlists); void SetManager(PlaylistManager *manager); void ReloadSettings(); diff --git a/src/playlist/playlistmanager.cpp b/src/playlist/playlistmanager.cpp index 6fbe8bf3a..313750fb6 100644 --- a/src/playlist/playlistmanager.cpp +++ b/src/playlist/playlistmanager.cpp @@ -65,6 +65,7 @@ #include "playlistview.h" #include "playlistsaveoptionsdialog.h" #include "playlistparsers/playlistparser.h" +#include "dialogs/saveplaylistsdialog.h" class ParserBase; @@ -271,7 +272,7 @@ void PlaylistManager::SaveWithUI(const int id, const QString &playlist_name) { PlaylistSettingsPage::PathType path_type = static_cast(s.value("path_type", PlaylistSettingsPage::PathType_Automatic).toInt()); s.endGroup(); if (path_type == PlaylistSettingsPage::PathType_Ask_User) { - PlaylistSaveOptionsDialog optionsdialog(nullptr); + PlaylistSaveOptionsDialog optionsdialog; optionsdialog.setModal(true); if (optionsdialog.exec() != QDialog::Accepted) return; path_type = optionsdialog.path_type(); @@ -628,3 +629,35 @@ void PlaylistManager::RateCurrentSong(const float rating) { void PlaylistManager::RateCurrentSong2(const int rating) { RateCurrentSong(static_cast(rating) / 5.0F); } + +void PlaylistManager::SaveAllPlaylists() { + + SavePlaylistsDialog dialog(parser()->file_extensions(PlaylistParser::Type_Save), parser()->default_extension()); + if (dialog.exec() != QDialog::Accepted) { + return; + } + + const QString path = dialog.path(); + if (path.isEmpty() || !QDir().exists(path)) return; + + QString extension = dialog.extension(); + if (extension.isEmpty()) extension = parser()->default_extension(); + + QSettings s; + s.beginGroup(PlaylistSettingsPage::kSettingsGroup); + PlaylistSettingsPage::PathType path_type = static_cast(s.value("path_type", PlaylistSettingsPage::PathType_Automatic).toInt()); + s.endGroup(); + if (path_type == PlaylistSettingsPage::PathType_Ask_User) { + PlaylistSaveOptionsDialog optionsdialog; + optionsdialog.setModal(true); + if (optionsdialog.exec() != QDialog::Accepted) return; + path_type = optionsdialog.path_type(); + } + + for (QMap::const_iterator it = playlists_.constBegin(); it != playlists_.constEnd(); ++it) { + const Data &data = *it; + const QString filepath = path + "/" + data.name + "." + extension; + Save(it.key(), filepath, path_type); + } + +} diff --git a/src/playlist/playlistmanager.h b/src/playlist/playlistmanager.h index 491e9d052..bb0271389 100644 --- a/src/playlist/playlistmanager.h +++ b/src/playlist/playlistmanager.h @@ -223,6 +223,8 @@ class PlaylistManager : public PlaylistManagerInterface { // Rate current song using 0 - 5 scale. void RateCurrentSong2(const int rating) override; + void SaveAllPlaylists(); + private slots: void SetActivePlaying() override; void SetActivePaused() override;