strawberry-audio-player-win.../src/core/mainwindow.cpp

3279 lines
126 KiB
C++
Raw Normal View History

2018-02-27 18:06:05 +01:00
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
2021-03-20 21:14:47 +01:00
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
2018-02-27 18:06:05 +01:00
*
* 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 <http://www.gnu.org/licenses/>.
2018-08-09 18:39:44 +02:00
*
2018-02-27 18:06:05 +01:00
*/
#include "config.h"
#include "version.h"
2018-02-27 18:06:05 +01:00
#include <cmath>
#include <functional>
2020-02-08 03:40:30 +01:00
#include <algorithm>
2021-09-26 20:06:04 +02:00
#include <chrono>
#include <memory>
2018-02-27 18:06:05 +01:00
2018-03-31 16:49:27 +02:00
#include <QMainWindow>
#include <QApplication>
#include <QObject>
#include <QWidget>
#include <QScreen>
#include <QMetaObject>
2020-02-08 03:40:30 +01:00
#include <QThread>
#include <QSortFilterProxyModel>
#include <QByteArray>
2018-02-27 18:06:05 +01:00
#include <QDir>
#include <QFile>
2018-02-27 18:06:05 +01:00
#include <QFileDialog>
#include <QFileInfo>
#include <QFontMetrics>
#include <QList>
#include <QSet>
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QIcon>
#include <QMimeData>
#include <QPalette>
#include <QTimer>
#include <QKeySequence>
2018-02-27 18:06:05 +01:00
#include <QMenu>
#include <QAction>
#include <QActionGroup>
#include <QShortcut>
2018-02-27 18:06:05 +01:00
#include <QMessageBox>
#include <QErrorMessage>
#include <QtEvents>
2018-02-27 18:06:05 +01:00
#include <QSettings>
2020-02-08 03:40:30 +01:00
#include <QColor>
#include <QFrame>
#include <QItemSelectionModel>
#include <QLabel>
#include <QLayout>
#include <QSize>
#include <QSplitter>
#include <QStackedWidget>
#include <QTabBar>
#include <QToolButton>
#include <QCheckBox>
#include <QClipboard>
#ifdef HAVE_DBUS
# include <QDBusConnection>
# include <QDBusMessage>
#endif
2018-02-27 18:06:05 +01:00
#include "core/logging.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "shared_ptr.h"
#include "commandlineoptions.h"
#include "mimedata.h"
#include "iconloader.h"
#include "taskmanager.h"
#include "song.h"
2019-04-25 00:00:49 +02:00
#include "stylehelper.h"
#include "stylesheetloader.h"
#include "application.h"
#include "database.h"
#include "player.h"
#include "filesystemmusicstorage.h"
#include "deletefiles.h"
2021-05-20 21:40:08 +02:00
#ifdef Q_OS_MACOS
# include "mac_startup.h"
2021-05-20 21:40:08 +02:00
# include "macsystemtrayicon.h"
2023-03-07 23:04:00 +01:00
# include "utilities/macosutils.h"
2021-05-20 21:40:08 +02:00
#else
# include "qtsystemtrayicon.h"
#endif
#include "networkaccessmanager.h"
#include "utilities/envutils.h"
#include "utilities/filemanagerutils.h"
#include "utilities/timeconstants.h"
#include "utilities/screenutils.h"
2018-02-27 18:06:05 +01:00
#include "engine/enginebase.h"
#include "dialogs/errordialog.h"
#include "dialogs/about.h"
#include "dialogs/console.h"
#include "dialogs/trackselectiondialog.h"
#include "dialogs/edittagdialog.h"
#include "dialogs/addstreamdialog.h"
#include "dialogs/deleteconfirmationdialog.h"
2020-08-30 18:09:13 +02:00
#include "dialogs/lastfmimportdialog.h"
2020-10-15 21:47:52 +02:00
#include "dialogs/snapdialog.h"
#include "organize/organizedialog.h"
#include "widgets/fancytabwidget.h"
#include "widgets/playingwidget.h"
2019-03-09 16:48:45 +01:00
#include "widgets/volumeslider.h"
#include "widgets/fileview.h"
#include "widgets/multiloadingindicator.h"
#include "widgets/trackslider.h"
2020-08-09 01:37:00 +02:00
#include "osd/osdbase.h"
#include "context/contextview.h"
2018-02-27 18:06:05 +01:00
#include "collection/collection.h"
#include "collection/collectionbackend.h"
#include "collection/collectiondirectorymodel.h"
#include "collection/collectionfilterwidget.h"
#include "collection/collectionmodel.h"
#include "collection/collectionview.h"
2018-02-27 18:06:05 +01:00
#include "collection/collectionviewcontainer.h"
#include "playlist/playlist.h"
#include "playlist/playlistbackend.h"
#include "playlist/playlistcontainer.h"
2018-02-27 18:06:05 +01:00
#include "playlist/playlistlistcontainer.h"
#include "playlist/playlistmanager.h"
#include "playlist/playlistsequence.h"
#include "playlist/playlistview.h"
2022-08-09 17:23:46 +02:00
#include "playlist/playlistfilter.h"
2018-10-21 15:13:48 +02:00
#include "queue/queue.h"
#include "queue/queueview.h"
2018-02-27 18:06:05 +01:00
#include "playlistparsers/playlistparser.h"
#include "analyzer/analyzercontainer.h"
#include "equalizer/equalizer.h"
#ifdef HAVE_GLOBALSHORTCUTS
2021-01-26 19:13:29 +01:00
# include "globalshortcuts/globalshortcutsmanager.h"
#endif
#include "covermanager/albumcovermanager.h"
#include "covermanager/albumcoverchoicecontroller.h"
#include "covermanager/albumcoverloaderresult.h"
#include "covermanager/currentalbumcoverloader.h"
2020-05-09 01:48:08 +02:00
#include "covermanager/coverproviders.h"
#include "covermanager/albumcoverimageresult.h"
#include "lyrics/lyricsproviders.h"
2018-09-20 17:36:23 +02:00
#ifndef Q_OS_WIN
# include "device/devicemanager.h"
# include "device/devicestatefiltermodel.h"
# include "device/deviceview.h"
# include "device/deviceviewcontainer.h"
#endif
2018-02-27 18:06:05 +01:00
#include "transcoder/transcodedialog.h"
#include "settings/settingsdialog.h"
2018-02-27 18:06:05 +01:00
#include "settings/behavioursettingspage.h"
2019-03-09 16:48:45 +01:00
#include "settings/backendsettingspage.h"
2023-07-21 05:25:57 +02:00
#include "settings/collectionsettingspage.h"
2018-02-27 18:06:05 +01:00
#include "settings/playlistsettingspage.h"
2019-06-17 23:54:24 +02:00
#ifdef HAVE_SUBSONIC
# include "settings/subsonicsettingspage.h"
#endif
2020-04-13 19:04:06 +02:00
#ifdef HAVE_TIDAL
# include "tidal/tidalservice.h"
# include "settings/tidalsettingspage.h"
#endif
#ifdef HAVE_QOBUZ
# include "settings/qobuzsettingspage.h"
#endif
2018-02-27 18:06:05 +01:00
#include "internet/internetservices.h"
2018-10-14 00:08:33 +02:00
#include "internet/internetservice.h"
2019-06-17 23:54:24 +02:00
#include "internet/internetsongsview.h"
#include "internet/internettabsview.h"
2020-02-08 03:40:30 +01:00
#include "internet/internetcollectionview.h"
#include "internet/internetsearchview.h"
2018-08-09 18:10:03 +02:00
2021-07-11 01:02:53 +02:00
#include "radios/radioservices.h"
#include "radios/radioviewcontainer.h"
#include "scrobbler/audioscrobbler.h"
2020-08-30 18:09:13 +02:00
#include "scrobbler/lastfmimport.h"
#ifdef HAVE_MUSICBRAINZ
2018-07-16 07:23:37 +02:00
# include "musicbrainz/tagfetcher.h"
#endif
2019-04-18 15:03:01 +02:00
#ifdef HAVE_MOODBAR
# include "moodbar/moodbarcontroller.h"
# include "moodbar/moodbarproxystyle.h"
#endif
#include "smartplaylists/smartplaylistsviewcontainer.h"
2020-10-17 21:10:57 +02:00
#ifdef Q_OS_WIN
2019-08-29 21:32:52 +02:00
# include "windows7thumbbar.h"
#endif
#ifdef HAVE_QTSPARKLE
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
# include <qtsparkle-qt6/Updater>
# else
# include <qtsparkle-qt5/Updater>
# endif
#endif // HAVE_QTSPARKLE
using std::make_unique;
using std::make_shared;
2021-08-25 02:57:09 +02:00
using namespace std::chrono_literals;
2018-02-27 18:06:05 +01:00
const char *MainWindow::kSettingsGroup = "MainWindow";
const char *MainWindow::kAllFilesFilterSpec = QT_TR_NOOP("All Files (*)");
namespace {
2018-10-02 01:01:31 +02:00
const int kTrackSliderUpdateTimeMs = 200;
2018-02-27 18:06:05 +01:00
const int kTrackPositionUpdateTimeMs = 1000;
2021-06-20 23:55:02 +02:00
} // namespace
2018-02-27 18:06:05 +01:00
#ifdef HAVE_QTSPARKLE
# ifdef _MSC_VER
# ifdef _M_X64
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-msvc-x64";
# else
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-msvc-x86";
# endif
# else
# ifdef __x86_64__
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-mingw-x64";
# else
constexpr char QTSPARKLE_URL[] = "https://www.strawberrymusicplayer.org/sparkle-windows-mingw-x86";
# endif
# endif
#endif
MainWindow::MainWindow(Application *app, SharedPtr<SystemTrayIcon> tray_icon, OSDBase *osd, const CommandlineOptions &options, QWidget *parent)
2021-07-11 07:40:57 +02:00
: QMainWindow(parent),
2018-02-27 18:06:05 +01:00
ui_(new Ui_MainWindow),
2020-10-17 21:10:57 +02:00
#ifdef Q_OS_WIN
2018-02-27 18:06:05 +01:00
thumbbar_(new Windows7ThumbBar(this)),
2019-08-29 21:32:52 +02:00
#endif
2018-02-27 18:06:05 +01:00
app_(app),
tray_icon_(tray_icon),
osd_(osd),
console_([app]() {
Console *console = new Console(app);
return console;
}),
2018-02-27 18:06:05 +01:00
edit_tag_dialog_(std::bind(&MainWindow::CreateEditTagDialog, this)),
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
#ifdef HAVE_GLOBALSHORTCUTS
2021-01-26 19:13:29 +01:00
globalshortcuts_manager_(new GlobalShortcutsManager(this)),
#endif
context_view_(new ContextView(this)),
2018-02-27 18:06:05 +01:00
collection_view_(new CollectionViewContainer(this)),
file_view_(new FileView(this)),
2018-09-20 17:36:23 +02:00
#ifndef Q_OS_WIN
device_view_(new DeviceViewContainer(this)),
2018-09-20 17:36:23 +02:00
#endif
playlist_list_(new PlaylistListContainer(this)),
2018-10-21 15:13:48 +02:00
queue_view_(new QueueView(this)),
2018-02-27 18:06:05 +01:00
settings_dialog_(std::bind(&MainWindow::CreateSettingsDialog, this)),
cover_manager_([this, app]() {
AlbumCoverManager *cover_manager = new AlbumCoverManager(app, app->collection_backend(), this);
2018-02-27 18:06:05 +01:00
cover_manager->Init();
// Cover manager connections
QObject::connect(cover_manager, &AlbumCoverManager::Error, this, &MainWindow::ShowErrorDialog);
2021-01-26 16:48:04 +01:00
QObject::connect(cover_manager, &AlbumCoverManager::AddToPlaylist, this, &MainWindow::AddToPlaylist);
2018-02-27 18:06:05 +01:00
return cover_manager;
}),
equalizer_(new Equalizer),
organize_dialog_([this, app]() {
OrganizeDialog *dialog = new OrganizeDialog(app->task_manager(), app->collection_backend(), this);
2018-02-27 18:06:05 +01:00
dialog->SetDestinationModel(app->collection()->model()->directory_model());
return dialog;
}),
2020-05-30 21:39:16 +02:00
#ifdef HAVE_GSTREAMER
transcode_dialog_([this]() {
TranscodeDialog *dialog = new TranscodeDialog(this);
return dialog;
}),
2020-05-30 21:39:16 +02:00
#endif
add_stream_dialog_([this]() {
AddStreamDialog *add_stream_dialog = new AddStreamDialog;
2021-01-26 16:48:04 +01:00
QObject::connect(add_stream_dialog, &AddStreamDialog::accepted, this, &MainWindow::AddStreamAccepted);
return add_stream_dialog;
}),
smartplaylists_view_(new SmartPlaylistsViewContainer(app, this)),
2019-06-17 23:54:24 +02:00
#ifdef HAVE_SUBSONIC
2023-02-18 14:09:27 +01:00
subsonic_view_(new InternetSongsView(app_, app->internet_services()->ServiceBySource(Song::Source::Subsonic), SubsonicSettingsPage::kSettingsGroup, SettingsDialog::Page::Subsonic, this)),
2020-04-13 19:04:06 +02:00
#endif
#ifdef HAVE_TIDAL
2023-02-18 14:09:27 +01:00
tidal_view_(new InternetTabsView(app_, app->internet_services()->ServiceBySource(Song::Source::Tidal), TidalSettingsPage::kSettingsGroup, SettingsDialog::Page::Tidal, this)),
#endif
#ifdef HAVE_QOBUZ
2023-02-18 14:09:27 +01:00
qobuz_view_(new InternetTabsView(app_, app->internet_services()->ServiceBySource(Song::Source::Qobuz), QobuzSettingsPage::kSettingsGroup, SettingsDialog::Page::Qobuz, this)),
2018-10-17 23:49:02 +02:00
#endif
2021-07-11 01:02:53 +02:00
radio_view_(new RadioViewContainer(this)),
2020-08-30 18:09:13 +02:00
lastfm_import_dialog_(new LastFMImportDialog(app_->lastfm_import(), this)),
collection_show_all_(nullptr),
collection_show_duplicates_(nullptr),
collection_show_untagged_(nullptr),
2018-02-27 18:06:05 +01:00
playlist_menu_(new QMenu(this)),
playlist_play_pause_(nullptr),
playlist_stop_after_(nullptr),
playlist_undoredo_(nullptr),
playlist_copy_url_(nullptr),
playlist_show_in_collection_(nullptr),
playlist_copy_to_collection_(nullptr),
playlist_move_to_collection_(nullptr),
playlist_open_in_browser_(nullptr),
playlist_organize_(nullptr),
#ifndef Q_OS_WIN
playlist_copy_to_device_(nullptr),
#endif
playlist_delete_(nullptr),
playlist_queue_(nullptr),
playlist_queue_play_next_(nullptr),
playlist_skip_(nullptr),
2018-02-27 18:06:05 +01:00
playlist_add_to_another_(nullptr),
playlistitem_actions_separator_(nullptr),
playlist_rescan_songs_(nullptr),
2018-02-27 18:06:05 +01:00
collection_sort_model_(new QSortFilterProxyModel(this)),
track_position_timer_(new QTimer(this)),
track_slider_timer_(new QTimer(this)),
keep_running_(false),
2019-03-09 17:20:07 +01:00
playing_widget_(true),
2023-02-18 14:09:27 +01:00
doubleclick_addmode_(BehaviourSettingsPage::AddBehaviour::Append),
doubleclick_playmode_(BehaviourSettingsPage::PlayBehaviour::Never),
doubleclick_playlist_addmode_(BehaviourSettingsPage::PlaylistAddBehaviour::Play),
menu_playmode_(BehaviourSettingsPage::PlayBehaviour::Never),
initialized_(false),
was_maximized_(true),
was_minimized_(false),
hidden_(false),
exit_(false),
exit_count_(0),
2022-05-21 19:12:22 +02:00
delete_files_(false),
ignore_close_(false) {
2018-02-27 18:06:05 +01:00
qLog(Debug) << "Starting";
2021-01-26 16:48:04 +01:00
QObject::connect(app, &Application::ErrorAdded, this, &MainWindow::ShowErrorDialog);
QObject::connect(app, &Application::SettingsDialogRequested, this, &MainWindow::OpenSettingsDialogAtPage);
2018-02-27 18:06:05 +01:00
2020-10-17 17:29:09 +02:00
// Initialize the UI
2018-02-27 18:06:05 +01:00
ui_->setupUi(this);
setWindowIcon(IconLoader::Load("strawberry"));
album_cover_choice_controller_->Init(app);
2018-02-27 18:06:05 +01:00
ui_->multi_loading_indicator->SetTaskManager(app_->task_manager());
2019-06-06 18:22:41 +02:00
context_view_->Init(app_, collection_view_->view(), album_cover_choice_controller_);
ui_->widget_playing->Init(app_, album_cover_choice_controller_);
2018-02-27 18:06:05 +01:00
2020-10-17 17:29:09 +02:00
// Initialize the search widget
2018-02-27 18:06:05 +01:00
StyleHelper::setBaseColor(palette().color(QPalette::Highlight).darker());
// Add tabs to the fancy tab widget
ui_->tabs->AddTab(context_view_, "context", IconLoader::Load("strawberry", true, 0, 32), tr("Context"));
ui_->tabs->AddTab(collection_view_, "collection", IconLoader::Load("library-music", true, 0, 32), tr("Collection"));
ui_->tabs->AddTab(queue_view_, "queue", IconLoader::Load("footsteps", true, 0, 32), tr("Queue"));
ui_->tabs->AddTab(playlist_list_, "playlists", IconLoader::Load("view-media-playlist", true, 0, 32), tr("Playlists"));
ui_->tabs->AddTab(smartplaylists_view_, "smartplaylists", IconLoader::Load("view-media-playlist", true, 0, 32), tr("Smart playlists"));
ui_->tabs->AddTab(file_view_, "files", IconLoader::Load("document-open", true, 0, 32), tr("Files"));
ui_->tabs->AddTab(radio_view_, "radios", IconLoader::Load("radio", true, 0, 32), tr("Radios"));
2018-09-20 17:36:23 +02:00
#ifndef Q_OS_WIN
ui_->tabs->AddTab(device_view_, "devices", IconLoader::Load("device", true, 0, 32), tr("Devices"));
2018-09-20 17:36:23 +02:00
#endif
2019-06-17 23:54:24 +02:00
#ifdef HAVE_SUBSONIC
ui_->tabs->AddTab(subsonic_view_, "subsonic", IconLoader::Load("subsonic", true, 0, 32), tr("Subsonic"));
2019-06-17 23:54:24 +02:00
#endif
2020-04-13 19:04:06 +02:00
#ifdef HAVE_TIDAL
ui_->tabs->AddTab(tidal_view_, "tidal", IconLoader::Load("tidal", true, 0, 32), tr("Tidal"));
2020-04-13 19:04:06 +02:00
#endif
#ifdef HAVE_QOBUZ
ui_->tabs->AddTab(qobuz_view_, "qobuz", IconLoader::Load("qobuz", true, 0, 32), tr("Qobuz"));
#endif
2018-02-27 18:06:05 +01:00
2018-08-09 21:49:18 +02:00
// Add the playing widget to the fancy tab widget
ui_->tabs->addBottomWidget(ui_->widget_playing);
2018-02-27 18:06:05 +01:00
//ui_->tabs->SetBackgroundPixmap(QPixmap(":/pictures/strawberry-background.png"));
ui_->tabs->Load(kSettingsGroup);
2018-02-27 18:06:05 +01:00
track_position_timer_->setInterval(kTrackPositionUpdateTimeMs);
2021-01-26 16:48:04 +01:00
QObject::connect(track_position_timer_, &QTimer::timeout, this, &MainWindow::UpdateTrackPosition);
2018-02-27 18:06:05 +01:00
track_slider_timer_->setInterval(kTrackSliderUpdateTimeMs);
2021-01-26 16:48:04 +01:00
QObject::connect(track_slider_timer_, &QTimer::timeout, this, &MainWindow::UpdateTrackSliderPosition);
2018-02-27 18:06:05 +01:00
2020-10-17 17:29:09 +02:00
// Start initializing the player
qLog(Debug) << "Initializing player";
2018-02-27 18:06:05 +01:00
app_->player()->SetAnalyzer(ui_->analyzer);
app_->player()->SetEqualizer(equalizer_);
2018-02-27 18:06:05 +01:00
app_->player()->Init();
EngineChanged(app_->player()->engine()->type());
2022-09-12 23:18:54 +02:00
const uint volume = app_->player()->GetVolume();
ui_->volume->SetValue(volume);
2019-03-09 16:48:45 +01:00
VolumeChanged(volume);
2018-02-27 18:06:05 +01:00
// Models
qLog(Debug) << "Creating models";
collection_sort_model_->setSourceModel(app_->collection()->model());
collection_sort_model_->setSortRole(CollectionModel::Role_SortText);
collection_sort_model_->setDynamicSortFilter(true);
collection_sort_model_->setSortLocaleAware(true);
collection_sort_model_->sort(0);
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
qLog(Debug) << "Creating models finished";
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->playlist, &PlaylistContainer::ViewSelectionModelChanged, this, &MainWindow::PlaylistViewSelectionModelChanged);
2018-02-27 18:06:05 +01:00
ui_->playlist->SetManager(app_->playlist_manager());
ui_->playlist->view()->Init(app_);
2018-02-27 18:06:05 +01:00
collection_view_->view()->setModel(collection_sort_model_);
collection_view_->view()->SetApplication(app_);
2018-09-20 17:36:23 +02:00
#ifndef Q_OS_WIN
device_view_->view()->SetApplication(app_);
2018-09-20 17:36:23 +02:00
#endif
2018-02-27 18:06:05 +01:00
playlist_list_->SetApplication(app_);
organize_dialog_->SetDestinationModel(app_->collection()->model()->directory_model());
2018-02-27 18:06:05 +01:00
2021-07-14 11:22:09 +02:00
radio_view_->view()->setModel(app_->radio_services()->sort_model());
2021-07-11 01:02:53 +02:00
2018-02-27 18:06:05 +01:00
// Icons
qLog(Debug) << "Creating UI";
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
// Help menu
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
ui_->action_about_strawberry->setIcon(IconLoader::Load("strawberry"));
ui_->action_about_qt->setIcon(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"));
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
// Music menu
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
ui_->action_open_file->setIcon(IconLoader::Load("document-open"));
ui_->action_open_cd->setIcon(IconLoader::Load("media-optical"));
2019-08-29 22:11:22 +02:00
ui_->action_previous_track->setIcon(IconLoader::Load("media-skip-backward"));
ui_->action_play_pause->setIcon(IconLoader::Load("media-playback-start"));
ui_->action_stop->setIcon(IconLoader::Load("media-playback-stop"));
ui_->action_stop_after_this_track->setIcon(IconLoader::Load("media-playback-stop"));
2019-08-29 22:11:22 +02:00
ui_->action_next_track->setIcon(IconLoader::Load("media-skip-forward"));
2018-10-02 00:46:54 +02:00
ui_->action_quit->setIcon(IconLoader::Load("application-exit"));
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
// Playlist
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
ui_->action_add_file->setIcon(IconLoader::Load("document-open"));
ui_->action_add_folder->setIcon(IconLoader::Load("document-open-folder"));
ui_->action_add_stream->setIcon(IconLoader::Load("document-open-remote"));
2018-02-27 18:06:05 +01:00
ui_->action_shuffle_mode->setIcon(IconLoader::Load("media-playlist-shuffle"));
ui_->action_repeat_mode->setIcon(IconLoader::Load("media-playlist-repeat"));
ui_->action_new_playlist->setIcon(IconLoader::Load("document-new"));
ui_->action_save_playlist->setIcon(IconLoader::Load("document-save"));
ui_->action_load_playlist->setIcon(IconLoader::Load("document-open"));
ui_->action_jump->setIcon(IconLoader::Load("go-jump"));
ui_->action_clear_playlist->setIcon(IconLoader::Load("edit-clear-list"));
ui_->action_shuffle->setIcon(IconLoader::Load("media-playlist-shuffle"));
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"));
2022-07-20 01:09:00 +02:00
ui_->action_save_all_playlists->setIcon(IconLoader::Load("document-save-all"));
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
// Configure
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
ui_->action_cover_manager->setIcon(IconLoader::Load("document-download"));
ui_->action_edit_track->setIcon(IconLoader::Load("edit-rename"));
ui_->action_edit_value->setIcon(IconLoader::Load("edit-rename"));
ui_->action_selection_set_value->setIcon(IconLoader::Load("edit-rename"));
2018-02-27 18:06:05 +01:00
ui_->action_equalizer->setIcon(IconLoader::Load("equalizer"));
ui_->action_transcoder->setIcon(IconLoader::Load("tools-wizard"));
2018-02-27 18:06:05 +01:00
ui_->action_update_collection->setIcon(IconLoader::Load("view-refresh"));
ui_->action_full_collection_scan->setIcon(IconLoader::Load("view-refresh"));
ui_->action_abort_collection_scan->setIcon(IconLoader::Load("dialog-error"));
2018-02-27 18:06:05 +01:00
ui_->action_settings->setIcon(IconLoader::Load("configure"));
2020-08-30 18:09:13 +02:00
ui_->action_import_data_from_last_fm->setIcon(IconLoader::Load("scrobble"));
ui_->action_console->setIcon(IconLoader::Load("keyboard"));
ui_->action_toggle_show_sidebar->setIcon(IconLoader::Load("view-choose"));
2021-11-09 20:07:48 +01:00
ui_->action_auto_complete_tags->setIcon(IconLoader::Load("musicbrainz"));
2019-01-06 16:48:23 +01:00
// Scrobble
2019-06-12 00:38:52 +02:00
ui_->action_toggle_scrobbling->setIcon(IconLoader::Load("scrobble-disabled"));
ui_->action_love->setIcon(IconLoader::Load("love"));
2018-02-27 18:06:05 +01:00
// File view connections
2021-01-26 16:48:04 +01:00
QObject::connect(file_view_, &FileView::AddToPlaylist, this, &MainWindow::AddToPlaylist);
QObject::connect(file_view_, &FileView::PathChanged, this, &MainWindow::FilePathChanged);
2018-02-27 18:06:05 +01:00
#ifdef HAVE_GSTREAMER
2021-01-26 16:48:04 +01:00
QObject::connect(file_view_, &FileView::CopyToCollection, this, &MainWindow::CopyFilesToCollection);
QObject::connect(file_view_, &FileView::MoveToCollection, this, &MainWindow::MoveFilesToCollection);
QObject::connect(file_view_, &FileView::EditTags, this, &MainWindow::EditFileTags);
2022-03-22 21:09:05 +01:00
# ifndef Q_OS_WIN
2021-01-26 16:48:04 +01:00
QObject::connect(file_view_, &FileView::CopyToDevice, this, &MainWindow::CopyFilesToDevice);
2022-03-22 21:09:05 +01:00
# endif
2018-02-27 18:06:05 +01:00
#endif
file_view_->SetTaskManager(app_->task_manager());
// Action connections
QObject::connect(ui_->action_next_track, &QAction::triggered, &*app_->player(), &Player::Next);
QObject::connect(ui_->action_previous_track, &QAction::triggered, &*app_->player(), &Player::Previous);
QObject::connect(ui_->action_play_pause, &QAction::triggered, &*app_->player(), &Player::PlayPauseHelper);
QObject::connect(ui_->action_stop, &QAction::triggered, &*app_->player(), &Player::Stop);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_quit, &QAction::triggered, this, &MainWindow::Exit);
QObject::connect(ui_->action_stop_after_this_track, &QAction::triggered, this, &MainWindow::StopAfterCurrent);
QObject::connect(ui_->action_mute, &QAction::triggered, &*app_->player(), &Player::Mute);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_clear_playlist, &QAction::triggered, this, &MainWindow::PlaylistClearCurrent);
QObject::connect(ui_->action_remove_duplicates, &QAction::triggered, &*app_->playlist_manager(), &PlaylistManager::RemoveDuplicatesCurrent);
QObject::connect(ui_->action_remove_unavailable, &QAction::triggered, &*app_->playlist_manager(), &PlaylistManager::RemoveUnavailableCurrent);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_remove_from_playlist, &QAction::triggered, this, &MainWindow::PlaylistRemoveCurrent);
QObject::connect(ui_->action_edit_track, &QAction::triggered, this, &MainWindow::EditTracks);
QObject::connect(ui_->action_renumber_tracks, &QAction::triggered, this, &MainWindow::RenumberTracks);
QObject::connect(ui_->action_selection_set_value, &QAction::triggered, this, &MainWindow::SelectionSetValue);
QObject::connect(ui_->action_edit_value, &QAction::triggered, this, &MainWindow::EditValue);
#ifdef HAVE_MUSICBRAINZ
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_auto_complete_tags, &QAction::triggered, this, &MainWindow::AutoCompleteTags);
#endif
QObject::connect(ui_->action_settings, &QAction::triggered, this, &MainWindow::OpenSettingsDialog);
QObject::connect(ui_->action_import_data_from_last_fm, &QAction::triggered, lastfm_import_dialog_, &LastFMImportDialog::show);
QObject::connect(ui_->action_toggle_show_sidebar, &QAction::toggled, this, &MainWindow::ToggleSidebar);
QObject::connect(ui_->action_about_strawberry, &QAction::triggered, this, &MainWindow::ShowAboutDialog);
QObject::connect(ui_->action_about_qt, &QAction::triggered, qApp, &QApplication::aboutQt);
QObject::connect(ui_->action_shuffle, &QAction::triggered, &*app_->playlist_manager(), &PlaylistManager::ShuffleCurrent);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_open_file, &QAction::triggered, this, &MainWindow::AddFile);
QObject::connect(ui_->action_open_cd, &QAction::triggered, this, &MainWindow::AddCDTracks);
QObject::connect(ui_->action_add_file, &QAction::triggered, this, &MainWindow::AddFile);
QObject::connect(ui_->action_add_folder, &QAction::triggered, this, &MainWindow::AddFolder);
QObject::connect(ui_->action_add_stream, &QAction::triggered, this, &MainWindow::AddStream);
QObject::connect(ui_->action_cover_manager, &QAction::triggered, this, &MainWindow::ShowCoverManager);
QObject::connect(ui_->action_equalizer, &QAction::triggered, this, &MainWindow::ShowEqualizer);
2019-01-06 16:48:23 +01:00
#if defined(HAVE_GSTREAMER)
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_transcoder, &QAction::triggered, this, &MainWindow::ShowTranscodeDialog);
2019-01-06 16:48:23 +01:00
#else
ui_->action_transcoder->setDisabled(true);
#endif
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_jump, &QAction::triggered, ui_->playlist->view(), &PlaylistView::JumpToCurrentlyPlayingTrack);
QObject::connect(ui_->action_update_collection, &QAction::triggered, &*app_->collection(), &SCollection::IncrementalScan);
QObject::connect(ui_->action_full_collection_scan, &QAction::triggered, &*app_->collection(), &SCollection::FullScan);
QObject::connect(ui_->action_abort_collection_scan, &QAction::triggered, &*app_->collection(), &SCollection::AbortScan);
2019-01-06 16:48:23 +01:00
#if defined(HAVE_GSTREAMER)
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_add_files_to_transcoder, &QAction::triggered, this, &MainWindow::AddFilesToTranscoder);
ui_->action_add_files_to_transcoder->setIcon(IconLoader::Load("tools-wizard"));
2019-01-06 16:48:23 +01:00
#else
ui_->action_add_files_to_transcoder->setDisabled(true);
#endif
2018-02-27 18:06:05 +01:00
QObject::connect(ui_->action_toggle_scrobbling, &QAction::triggered, &*app_->scrobbler(), &AudioScrobbler::ToggleScrobbling);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->action_love, &QAction::triggered, this, &MainWindow::Love);
QObject::connect(&*app_->scrobbler(), &AudioScrobbler::ErrorMessage, this, &MainWindow::ShowErrorDialog);
2018-02-27 18:06:05 +01:00
// Playlist view actions
2022-03-22 21:09:05 +01:00
ui_->action_next_playlist->setShortcuts(QList<QKeySequence>() << QKeySequence::fromString("Ctrl+Tab") << QKeySequence::fromString("Ctrl+PgDown"));
ui_->action_previous_playlist->setShortcuts(QList<QKeySequence>() << QKeySequence::fromString("Ctrl+Shift+Tab") << QKeySequence::fromString("Ctrl+PgUp"));
2018-02-27 18:06:05 +01:00
// Actions for switching tabs will be global to the entire window, so adding them here
addAction(ui_->action_next_playlist);
addAction(ui_->action_previous_playlist);
// Give actions to buttons
ui_->forward_button->setDefaultAction(ui_->action_next_track);
ui_->back_button->setDefaultAction(ui_->action_previous_track);
ui_->pause_play_button->setDefaultAction(ui_->action_play_pause);
ui_->stop_button->setDefaultAction(ui_->action_stop);
ui_->button_scrobble->setDefaultAction(ui_->action_toggle_scrobbling);
2019-06-12 00:38:52 +02:00
ui_->button_love->setDefaultAction(ui_->action_love);
2018-02-27 18:06:05 +01:00
2022-07-20 01:09:00 +02:00
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);
2018-02-27 18:06:05 +01:00
// 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());
// Stop actions
QMenu *stop_menu = new QMenu(this);
2018-02-27 18:06:05 +01:00
stop_menu->addAction(ui_->action_stop);
stop_menu->addAction(ui_->action_stop_after_this_track);
ui_->stop_button->setMenu(stop_menu);
// Player connections
QObject::connect(ui_->volume, &VolumeSlider::valueChanged, &*app_->player(), &Player::SetVolumeFromSlider);
QObject::connect(&*app_->player(), &Player::EngineChanged, this, &MainWindow::EngineChanged);
QObject::connect(&*app_->player(), &Player::Error, this, &MainWindow::ShowErrorDialog);
QObject::connect(&*app_->player(), &Player::SongChangeRequestProcessed, &*app_->playlist_manager(), &PlaylistManager::SongChangeRequestProcessed);
QObject::connect(&*app_->player(), &Player::Paused, this, &MainWindow::MediaPaused);
QObject::connect(&*app_->player(), &Player::Playing, this, &MainWindow::MediaPlaying);
QObject::connect(&*app_->player(), &Player::Stopped, this, &MainWindow::MediaStopped);
QObject::connect(&*app_->player(), &Player::Seeked, this, &MainWindow::Seeked);
QObject::connect(&*app_->player(), &Player::TrackSkipped, this, &MainWindow::TrackSkipped);
QObject::connect(&*app_->player(), &Player::VolumeChanged, this, &MainWindow::VolumeChanged);
QObject::connect(&*app_->player(), &Player::Paused, ui_->playlist, &PlaylistContainer::ActivePaused);
QObject::connect(&*app_->player(), &Player::Playing, ui_->playlist, &PlaylistContainer::ActivePlaying);
QObject::connect(&*app_->player(), &Player::Stopped, ui_->playlist, &PlaylistContainer::ActiveStopped);
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, osd_, &OSDBase::SongChanged);
QObject::connect(&*app_->player(), &Player::Paused, osd_, &OSDBase::Paused);
QObject::connect(&*app_->player(), &Player::Resumed, osd_, &OSDBase::Resumed);
QObject::connect(&*app_->player(), &Player::Stopped, osd_, &OSDBase::Stopped);
QObject::connect(&*app_->player(), &Player::PlaylistFinished, osd_, &OSDBase::PlaylistFinished);
QObject::connect(&*app_->player(), &Player::VolumeChanged, osd_, &OSDBase::VolumeChanged);
QObject::connect(&*app_->player(), &Player::VolumeChanged, ui_->volume, &VolumeSlider::SetValue);
QObject::connect(&*app_->player(), &Player::ForceShowOSD, this, &MainWindow::ForceShowOSD);
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, this, &MainWindow::SongChanged);
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, &*app_->player(), &Player::CurrentMetadataChanged);
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::EditingFinished, this, &MainWindow::PlaylistEditFinished);
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::Error, this, &MainWindow::ShowErrorDialog);
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::SummaryTextChanged, ui_->playlist_summary, &QLabel::setText);
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::PlayRequested, this, &MainWindow::PlayIndex);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->playlist->view(), &PlaylistView::doubleClicked, this, &MainWindow::PlaylistDoubleClick);
QObject::connect(ui_->playlist->view(), &PlaylistView::PlayItem, this, &MainWindow::PlayIndex);
QObject::connect(ui_->playlist->view(), &PlaylistView::PlayPause, &*app_->player(), &Player::PlayPause);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->playlist->view(), &PlaylistView::RightClicked, this, &MainWindow::PlaylistRightClick);
QObject::connect(ui_->playlist->view(), &PlaylistView::SeekForward, &*app_->player(), &Player::SeekForward);
QObject::connect(ui_->playlist->view(), &PlaylistView::SeekBackward, &*app_->player(), &Player::SeekBackward);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->playlist->view(), &PlaylistView::BackgroundPropertyChanged, this, &MainWindow::RefreshStyleSheet);
QObject::connect(ui_->track_slider, &TrackSlider::ValueChangedSeconds, &*app_->player(), &Player::SeekTo);
QObject::connect(ui_->track_slider, &TrackSlider::SeekForward, &*app_->player(), &Player::SeekForward);
QObject::connect(ui_->track_slider, &TrackSlider::SeekBackward, &*app_->player(), &Player::SeekBackward);
QObject::connect(ui_->track_slider, &TrackSlider::Previous, &*app_->player(), &Player::Previous);
QObject::connect(ui_->track_slider, &TrackSlider::Next, &*app_->player(), &Player::Next);
2018-09-08 12:38:02 +02:00
2018-02-27 18:06:05 +01:00
// Collection connections
QObject::connect(&*app_->collection(), &SCollection::Error, this, &MainWindow::ShowErrorDialog);
2021-01-26 16:48:04 +01:00
QObject::connect(collection_view_->view(), &CollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
QObject::connect(collection_view_->view(), &CollectionView::ShowConfigDialog, this, &MainWindow::ShowCollectionConfig);
QObject::connect(collection_view_->view(), &CollectionView::Error, this, &MainWindow::ShowErrorDialog);
QObject::connect(app_->collection_model(), &CollectionModel::TotalSongCountUpdated, collection_view_->view(), &CollectionView::TotalSongCountUpdated);
QObject::connect(app_->collection_model(), &CollectionModel::TotalArtistCountUpdated, collection_view_->view(), &CollectionView::TotalArtistCountUpdated);
2021-07-11 09:49:38 +02:00
QObject::connect(app_->collection_model(), &CollectionModel::TotalAlbumCountUpdated, collection_view_->view(), &CollectionView::TotalAlbumCountUpdated);
QObject::connect(app_->collection_model(), &CollectionModel::modelAboutToBeReset, collection_view_->view(), &CollectionView::SaveFocus);
2021-01-26 16:48:04 +01:00
QObject::connect(app_->collection_model(), &CollectionModel::modelReset, collection_view_->view(), &CollectionView::RestoreFocus);
QObject::connect(&*app_->task_manager(), &TaskManager::PauseCollectionWatchers, &*app_->collection(), &SCollection::PauseWatcher);
QObject::connect(&*app_->task_manager(), &TaskManager::ResumeCollectionWatchers, &*app_->collection(), &SCollection::ResumeWatcher);
2021-01-26 16:48:04 +01:00
QObject::connect(&*app_->current_albumcover_loader(), &CurrentAlbumCoverLoader::AlbumCoverLoaded, this, &MainWindow::AlbumCoverLoaded);
QObject::connect(album_cover_choice_controller_, &AlbumCoverChoiceController::Error, this, &MainWindow::ShowErrorDialog);
2021-01-26 16:48:04 +01:00
QObject::connect(album_cover_choice_controller_->cover_from_file_action(), &QAction::triggered, this, &MainWindow::LoadCoverFromFile);
QObject::connect(album_cover_choice_controller_->cover_to_file_action(), &QAction::triggered, this, &MainWindow::SaveCoverToFile);
QObject::connect(album_cover_choice_controller_->cover_from_url_action(), &QAction::triggered, this, &MainWindow::LoadCoverFromURL);
QObject::connect(album_cover_choice_controller_->search_for_cover_action(), &QAction::triggered, this, &MainWindow::SearchForCover);
QObject::connect(album_cover_choice_controller_->unset_cover_action(), &QAction::triggered, this, &MainWindow::UnsetCover);
QObject::connect(album_cover_choice_controller_->clear_cover_action(), &QAction::triggered, this, &MainWindow::ClearCover);
QObject::connect(album_cover_choice_controller_->delete_cover_action(), &QAction::triggered, this, &MainWindow::DeleteCover);
2021-01-26 16:48:04 +01:00
QObject::connect(album_cover_choice_controller_->show_cover_action(), &QAction::triggered, this, &MainWindow::ShowCover);
QObject::connect(album_cover_choice_controller_->search_cover_auto_action(), &QAction::triggered, this, &MainWindow::SearchCoverAutomatically);
QObject::connect(album_cover_choice_controller_->search_cover_auto_action(), &QAction::toggled, this, &MainWindow::ToggleSearchCoverAuto);
2018-09-20 17:36:23 +02:00
#ifndef Q_OS_WIN
2018-02-27 18:06:05 +01:00
// Devices connections
2021-01-26 16:48:04 +01:00
QObject::connect(device_view_->view(), &DeviceView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
2018-09-20 17:36:23 +02:00
#endif
2018-02-27 18:06:05 +01:00
// Collection filter widget
QActionGroup *collection_view_group = new QActionGroup(this);
2018-02-27 18:06:05 +01:00
collection_show_all_ = collection_view_group->addAction(tr("Show all songs"));
collection_show_duplicates_ = collection_view_group->addAction(tr("Show only duplicates"));
collection_show_untagged_ = collection_view_group->addAction(tr("Show only untagged"));
collection_show_all_->setCheckable(true);
collection_show_duplicates_->setCheckable(true);
collection_show_untagged_->setCheckable(true);
collection_show_all_->setChecked(true);
QObject::connect(collection_view_group, &QActionGroup::triggered, this, &MainWindow::ChangeCollectionFilterMode);
2018-02-27 18:06:05 +01:00
QAction *collection_config_action = new QAction(IconLoader::Load("configure"), tr("Configure collection..."), this);
2021-01-26 16:48:04 +01:00
QObject::connect(collection_config_action, &QAction::triggered, this, &MainWindow::ShowCollectionConfig);
2021-06-28 00:07:58 +02:00
collection_view_->filter_widget()->SetSettingsGroup(CollectionSettingsPage::kSettingsGroup);
collection_view_->filter_widget()->Init(app_->collection()->model());
2018-02-27 18:06:05 +01:00
QAction *separator = new QAction(this);
2018-02-27 18:06:05 +01:00
separator->setSeparator(true);
2021-06-28 00:07:58 +02:00
collection_view_->filter_widget()->AddMenuAction(collection_show_all_);
collection_view_->filter_widget()->AddMenuAction(collection_show_duplicates_);
collection_view_->filter_widget()->AddMenuAction(collection_show_untagged_);
collection_view_->filter_widget()->AddMenuAction(separator);
collection_view_->filter_widget()->AddMenuAction(collection_config_action);
2018-02-27 18:06:05 +01:00
2019-06-17 23:54:24 +02:00
#ifdef HAVE_SUBSONIC
2021-01-26 16:48:04 +01:00
QObject::connect(subsonic_view_->view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
2019-06-17 23:54:24 +02:00
#endif
2020-04-13 19:04:06 +02:00
#ifdef HAVE_TIDAL
2021-01-26 16:48:04 +01:00
QObject::connect(tidal_view_->artists_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
QObject::connect(tidal_view_->albums_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
QObject::connect(tidal_view_->songs_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
QObject::connect(tidal_view_->search_view(), &InternetSearchView::AddToPlaylist, this, &MainWindow::AddToPlaylist);
if (TidalServicePtr tidalservice = app_->internet_services()->Service<TidalService>()) {
QObject::connect(this, &MainWindow::AuthorizationUrlReceived, &*tidalservice, &TidalService::AuthorizationUrlReceived);
2021-08-23 21:21:08 +02:00
}
2020-04-13 19:04:06 +02:00
#endif
#ifdef HAVE_QOBUZ
2021-01-26 16:48:04 +01:00
QObject::connect(qobuz_view_->artists_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
QObject::connect(qobuz_view_->albums_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
QObject::connect(qobuz_view_->songs_collection_view(), &InternetCollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
QObject::connect(qobuz_view_->search_view(), &InternetSearchView::AddToPlaylist, this, &MainWindow::AddToPlaylist);
#endif
QObject::connect(radio_view_, &RadioViewContainer::Refresh, &*app_->radio_services(), &RadioServices::RefreshChannels);
QObject::connect(radio_view_->view(), &RadioView::GetChannels, &*app_->radio_services(), &RadioServices::GetChannels);
2021-07-11 01:02:53 +02:00
QObject::connect(radio_view_->view(), &RadioView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
2018-02-27 18:06:05 +01:00
// Playlist menu
2021-01-26 16:48:04 +01:00
QObject::connect(playlist_menu_, &QMenu::aboutToHide, this, &MainWindow::PlaylistMenuHidden);
playlist_play_pause_ = playlist_menu_->addAction(tr("Play"), this, &MainWindow::PlaylistPlay);
2018-02-27 18:06:05 +01:00
playlist_menu_->addAction(ui_->action_stop);
2021-01-26 16:48:04 +01:00
playlist_stop_after_ = playlist_menu_->addAction(IconLoader::Load("media-playback-stop"), tr("Stop after this track"), this, &MainWindow::PlaylistStopAfter);
playlist_queue_ = playlist_menu_->addAction(IconLoader::Load("go-next"), tr("Toggle queue status"), this, &MainWindow::PlaylistQueue);
2018-02-27 18:06:05 +01:00
playlist_queue_->setShortcut(QKeySequence("Ctrl+D"));
ui_->playlist->addAction(playlist_queue_);
2021-01-26 16:48:04 +01:00
playlist_queue_play_next_ = playlist_menu_->addAction(IconLoader::Load("go-next"), tr("Queue selected tracks to play next"), this, &MainWindow::PlaylistQueuePlayNext);
playlist_queue_play_next_->setShortcut(QKeySequence("Ctrl+Shift+D"));
ui_->playlist->addAction(playlist_queue_play_next_);
2021-01-26 16:48:04 +01:00
playlist_skip_ = playlist_menu_->addAction(IconLoader::Load("media-skip-forward"), tr("Toggle skip status"), this, &MainWindow::PlaylistSkip);
2018-02-27 18:06:05 +01:00
ui_->playlist->addAction(playlist_skip_);
playlist_menu_->addSeparator();
playlist_menu_->addAction(ui_->action_remove_from_playlist);
playlist_undoredo_ = playlist_menu_->addSeparator();
playlist_menu_->addAction(ui_->action_edit_track);
playlist_menu_->addAction(ui_->action_edit_value);
playlist_menu_->addAction(ui_->action_renumber_tracks);
playlist_menu_->addAction(ui_->action_selection_set_value);
#ifdef HAVE_MUSICBRAINZ
2018-02-27 18:06:05 +01:00
playlist_menu_->addAction(ui_->action_auto_complete_tags);
#endif
2021-01-26 16:48:04 +01:00
playlist_rescan_songs_ = playlist_menu_->addAction(IconLoader::Load("view-refresh"), tr("Rescan song(s)..."), this, &MainWindow::RescanSongs);
playlist_menu_->addAction(playlist_rescan_songs_);
2019-01-06 16:48:23 +01:00
#ifdef HAVE_GSTREAMER
playlist_menu_->addAction(ui_->action_add_files_to_transcoder);
2019-01-06 16:48:23 +01:00
#endif
2018-02-27 18:06:05 +01:00
playlist_menu_->addSeparator();
2021-01-26 16:48:04 +01:00
playlist_copy_url_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy URL(s)..."), this, &MainWindow::PlaylistCopyUrl);
playlist_show_in_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-find"), tr("Show in collection..."), this, &MainWindow::ShowInCollection);
playlist_open_in_browser_ = playlist_menu_->addAction(IconLoader::Load("document-open-folder"), tr("Show in file browser..."), this, &MainWindow::PlaylistOpenInBrowser);
playlist_organize_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Organize files..."), this, &MainWindow::PlaylistMoveToCollection);
playlist_copy_to_collection_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy to collection..."), this, &MainWindow::PlaylistCopyToCollection);
playlist_move_to_collection_ = playlist_menu_->addAction(IconLoader::Load("go-jump"), tr("Move to collection..."), this, &MainWindow::PlaylistMoveToCollection);
2019-01-06 16:48:23 +01:00
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
2021-01-26 16:48:04 +01:00
playlist_copy_to_device_ = playlist_menu_->addAction(IconLoader::Load("device"), tr("Copy to device..."), this, &MainWindow::PlaylistCopyToDevice);
2019-01-06 16:48:23 +01:00
#endif
2021-01-26 16:48:04 +01:00
playlist_delete_ = playlist_menu_->addAction(IconLoader::Load("edit-delete"), tr("Delete from disk..."), this, &MainWindow::PlaylistDelete);
2018-02-27 18:06:05 +01:00
playlist_menu_->addSeparator();
playlistitem_actions_separator_ = playlist_menu_->addSeparator();
playlist_menu_->addAction(ui_->action_clear_playlist);
playlist_menu_->addAction(ui_->action_shuffle);
playlist_menu_->addAction(ui_->action_remove_duplicates);
playlist_menu_->addAction(ui_->action_remove_unavailable);
2018-07-01 22:26:46 +02:00
#ifdef Q_OS_MACOS
2018-02-27 18:06:05 +01:00
ui_->action_shuffle->setShortcut(QKeySequence());
#endif
// We have to add the actions on the playlist menu to this QWidget otherwise their shortcut keys don't work
2018-02-27 18:06:05 +01:00
addActions(playlist_menu_->actions());
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->playlist, &PlaylistContainer::UndoRedoActionsChanged, this, &MainWindow::PlaylistUndoRedoChanged);
2018-02-27 18:06:05 +01:00
2018-09-20 17:36:23 +02:00
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
2018-02-27 18:06:05 +01:00
playlist_copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
2021-01-26 16:48:04 +01:00
QObject::connect(app_->device_manager()->connected_devices_model(), &DeviceStateFilterModel::IsEmptyChanged, playlist_copy_to_device_, &QAction::setDisabled);
2018-02-27 18:06:05 +01:00
#endif
QObject::connect(&*app_->scrobbler()->settings(), &ScrobblerSettings::ScrobblingEnabledChanged, this, &MainWindow::ScrobblingEnabledChanged);
QObject::connect(&*app_->scrobbler()->settings(), &ScrobblerSettings::ScrobbleButtonVisibilityChanged, this, &MainWindow::ScrobbleButtonVisibilityChanged);
QObject::connect(&*app_->scrobbler()->settings(), &ScrobblerSettings::LoveButtonVisibilityChanged, this, &MainWindow::LoveButtonVisibilityChanged);
2018-07-01 22:26:46 +02:00
#ifdef Q_OS_MACOS
2018-02-27 18:06:05 +01:00
mac::SetApplicationHandler(this);
#endif
// Tray icon
tray_icon_->SetupMenu(ui_->action_previous_track, ui_->action_play_pause, ui_->action_stop, ui_->action_stop_after_this_track, ui_->action_next_track, ui_->action_mute, ui_->action_love, ui_->action_quit);
QObject::connect(&*tray_icon_, &SystemTrayIcon::PlayPause, &*app_->player(), &Player::PlayPauseHelper);
QObject::connect(&*tray_icon_, &SystemTrayIcon::SeekForward, &*app_->player(), &Player::SeekForward);
QObject::connect(&*tray_icon_, &SystemTrayIcon::SeekBackward, &*app_->player(), &Player::SeekBackward);
QObject::connect(&*tray_icon_, &SystemTrayIcon::NextTrack, &*app_->player(), &Player::Next);
QObject::connect(&*tray_icon_, &SystemTrayIcon::PreviousTrack, &*app_->player(), &Player::Previous);
QObject::connect(&*tray_icon_, &SystemTrayIcon::ShowHide, this, &MainWindow::ToggleShowHide);
QObject::connect(&*tray_icon_, &SystemTrayIcon::ChangeVolume, this, &MainWindow::VolumeWheelEvent);
2018-02-27 18:06:05 +01:00
// Windows 7 thumbbar buttons
2020-10-17 21:10:57 +02:00
#ifdef Q_OS_WIN
2019-06-12 00:38:52 +02:00
thumbbar_->SetActions(QList<QAction*>() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr << ui_->action_love);
2019-08-29 21:32:52 +02:00
#endif
2018-02-27 18:06:05 +01:00
2022-01-15 02:19:43 +01:00
#if defined(HAVE_QTSPARKLE)
QAction *check_updates = ui_->menu_tools->addAction(tr("Check for updates..."));
2018-02-27 18:06:05 +01:00
check_updates->setMenuRole(QAction::ApplicationSpecificRole);
#endif
#ifdef HAVE_GLOBALSHORTCUTS
2018-02-27 18:06:05 +01:00
// Global shortcuts
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::Play, &*app_->player(), &Player::PlayHelper);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::Pause, &*app_->player(), &Player::Pause);
2021-01-26 19:13:29 +01:00
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::PlayPause, ui_->action_play_pause, &QAction::trigger);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::Stop, ui_->action_stop, &QAction::trigger);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::StopAfter, ui_->action_stop_after_this_track, &QAction::trigger);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::Next, ui_->action_next_track, &QAction::trigger);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::Previous, ui_->action_previous_track, &QAction::trigger);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::IncVolume, &*app_->player(), &Player::VolumeUp);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::DecVolume, &*app_->player(), &Player::VolumeDown);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::Mute, &*app_->player(), &Player::Mute);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::SeekForward, &*app_->player(), &Player::SeekForward);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::SeekBackward, &*app_->player(), &Player::SeekBackward);
2021-01-26 19:13:29 +01:00
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::ShowHide, this, &MainWindow::ToggleShowHide);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::ShowOSD, &*app_->player(), &Player::ShowOSD);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::TogglePrettyOSD, &*app_->player(), &Player::TogglePrettyOSD);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::ToggleScrobbling, &*app_->scrobbler(), &AudioScrobbler::ToggleScrobbling);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::Love, &*app_->scrobbler(), &AudioScrobbler::Love);
#endif
2018-02-27 18:06:05 +01:00
// Fancy tabs
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->tabs, &FancyTabWidget::CurrentChanged, this, &MainWindow::TabSwitched);
2018-10-02 00:38:52 +02:00
// Context
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, context_view_, &ContextView::SongChanged);
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::SongMetadataChanged, context_view_, &ContextView::SongChanged);
QObject::connect(&*app_->player(), &Player::PlaylistFinished, context_view_, &ContextView::Stopped);
QObject::connect(&*app_->player(), &Player::Playing, context_view_, &ContextView::Playing);
QObject::connect(&*app_->player(), &Player::Stopped, context_view_, &ContextView::Stopped);
QObject::connect(&*app_->player(), &Player::Error, context_view_, &ContextView::Error);
2021-01-26 16:48:04 +01:00
QObject::connect(this, &MainWindow::AlbumCoverReady, context_view_, &ContextView::AlbumCoverLoaded);
QObject::connect(this, &MainWindow::SearchCoverInProgress, context_view_->album_widget(), &ContextAlbum::SearchCoverInProgress);
QObject::connect(context_view_, &ContextView::AlbumEnabledChanged, this, &MainWindow::TabSwitched);
2018-02-27 18:06:05 +01:00
// Analyzer
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->analyzer, &AnalyzerContainer::WheelEvent, this, &MainWindow::VolumeWheelEvent);
2018-02-27 18:06:05 +01:00
// Statusbar widgets
ui_->playlist_summary->setMinimumWidth(QFontMetrics(font()).horizontalAdvance("WW selected of WW tracks - [ WW:WW ]"));
2018-02-27 18:06:05 +01:00
ui_->status_bar_stack->setCurrentWidget(ui_->playlist_summary_page);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->multi_loading_indicator, &MultiLoadingIndicator::TaskCountChange, this, &MainWindow::TaskCountChanged);
2018-02-27 18:06:05 +01:00
ui_->track_slider->SetApplication(app);
2019-04-18 15:03:01 +02:00
#ifdef HAVE_MOODBAR
// Moodbar connections
QObject::connect(&*app_->moodbar_controller(), &MoodbarController::CurrentMoodbarDataChanged, ui_->track_slider->moodbar_style(), &MoodbarProxyStyle::SetMoodbarData);
2019-04-18 15:03:01 +02:00
#endif
2018-08-09 21:49:18 +02:00
// Playing widget
qLog(Debug) << "Creating playing widget";
ui_->widget_playing->set_ideal_height(ui_->status_bar->sizeHint().height() + ui_->player_controls->sizeHint().height());
QObject::connect(&*app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, ui_->widget_playing, &PlayingWidget::SongChanged);
QObject::connect(&*app_->player(), &Player::PlaylistFinished, ui_->widget_playing, &PlayingWidget::Stopped);
QObject::connect(&*app_->player(), &Player::Playing, ui_->widget_playing, &PlayingWidget::Playing);
QObject::connect(&*app_->player(), &Player::Stopped, ui_->widget_playing, &PlayingWidget::Stopped);
QObject::connect(&*app_->player(), &Player::Error, ui_->widget_playing, &PlayingWidget::Error);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->widget_playing, &PlayingWidget::ShowAboveStatusBarChanged, this, &MainWindow::PlayingWidgetPositionChanged);
QObject::connect(this, &MainWindow::AlbumCoverReady, ui_->widget_playing, &PlayingWidget::AlbumCoverLoaded);
QObject::connect(this, &MainWindow::SearchCoverInProgress, ui_->widget_playing, &PlayingWidget::SearchCoverInProgress);
QObject::connect(ui_->action_console, &QAction::triggered, this, &MainWindow::ShowConsole);
PlayingWidgetPositionChanged(ui_->widget_playing->show_above_status_bar());
2018-02-27 18:06:05 +01:00
StyleSheetLoader *css_loader = new StyleSheetLoader(this);
css_loader->SetStyleSheet(this, ":/style/strawberry.css");
2018-02-27 18:06:05 +01:00
// Load playlists
app_->playlist_manager()->Init(app_->collection_backend(), app_->playlist_backend(), ui_->playlist_sequence, ui_->playlist);
2018-10-21 15:13:48 +02:00
queue_view_->SetPlaylistManager(app_->playlist_manager());
2018-02-27 18:06:05 +01:00
// This connection must be done after the playlists have been initialized.
2021-01-26 16:48:04 +01:00
QObject::connect(this, &MainWindow::StopAfterToggled, osd_, &OSDBase::StopAfterToggle);
2018-02-27 18:06:05 +01:00
// We need to connect these global shortcuts here after the playlist have been initialized
#ifdef HAVE_GLOBALSHORTCUTS
2021-01-26 19:13:29 +01:00
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::CycleShuffleMode, app_->playlist_manager()->sequence(), &PlaylistSequence::CycleShuffleMode);
QObject::connect(globalshortcuts_manager_, &GlobalShortcutsManager::CycleRepeatMode, app_->playlist_manager()->sequence(), &PlaylistSequence::CycleRepeatMode);
#endif
2021-01-26 16:48:04 +01:00
QObject::connect(app_->playlist_manager()->sequence(), &PlaylistSequence::RepeatModeChanged, osd_, &OSDBase::RepeatModeChanged);
QObject::connect(app_->playlist_manager()->sequence(), &PlaylistSequence::ShuffleModeChanged, osd_, &OSDBase::ShuffleModeChanged);
2018-02-27 18:06:05 +01:00
// Smart playlists
2021-01-26 16:48:04 +01:00
QObject::connect(smartplaylists_view_, &SmartPlaylistsViewContainer::AddToPlaylist, this, &MainWindow::AddToPlaylist);
ScrobbleButtonVisibilityChanged(app_->scrobbler()->scrobble_button());
LoveButtonVisibilityChanged(app_->scrobbler()->love_button());
ScrobblingEnabledChanged(app_->scrobbler()->enabled());
2020-08-30 18:09:13 +02:00
// Last.fm ImportData
QObject::connect(&*app_->lastfm_import(), &LastFMImport::Finished, lastfm_import_dialog_, &LastFMImportDialog::Finished);
QObject::connect(&*app_->lastfm_import(), &LastFMImport::FinishedWithError, lastfm_import_dialog_, &LastFMImportDialog::FinishedWithError);
QObject::connect(&*app_->lastfm_import(), &LastFMImport::UpdateTotal, lastfm_import_dialog_, &LastFMImportDialog::UpdateTotal);
QObject::connect(&*app_->lastfm_import(), &LastFMImport::UpdateProgress, lastfm_import_dialog_, &LastFMImportDialog::UpdateProgress);
2020-08-30 18:09:13 +02:00
2018-02-27 18:06:05 +01:00
// Load settings
qLog(Debug) << "Loading settings";
settings_.beginGroup(kSettingsGroup);
// Set last used geometry to position window on the correct monitor
// Set window state only if the window was last maximized
if (settings_.contains("geometry")) {
restoreGeometry(settings_.value("geometry").toByteArray());
}
2018-02-27 18:06:05 +01:00
if (!settings_.contains("splitter_state") || !ui_->splitter->restoreState(settings_.value("splitter_state").toByteArray())) {
ui_->splitter->setSizes(QList<int>() << 20 << (width() - 20));
2018-02-27 18:06:05 +01:00
}
ui_->tabs->setCurrentIndex(settings_.value("current_tab", 1).toInt());
2023-02-18 14:09:27 +01:00
FancyTabWidget::Mode default_mode = FancyTabWidget::Mode::LargeSidebar;
FancyTabWidget::Mode tab_mode = static_cast<FancyTabWidget::Mode>(settings_.value("tab_mode", static_cast<int>(default_mode)).toInt());
if (tab_mode == FancyTabWidget::Mode::None) tab_mode = default_mode;
ui_->tabs->SetMode(tab_mode);
2018-02-27 18:06:05 +01:00
TabSwitched();
file_view_->SetPath(settings_.value("file_path", QDir::homePath()).toString());
// Users often collapse one side of the splitter by mistake and don't know how to restore it. This must be set after the state is restored above.
2018-02-27 18:06:05 +01:00
ui_->splitter->setChildrenCollapsible(false);
ReloadSettings();
// Reload pretty OSD to avoid issues with fonts
osd_->ReloadPrettyOSDSettings();
// Reload playlist settings, for BG and glowing
ui_->playlist->view()->ReloadSettings();
2021-07-11 09:49:38 +02:00
#ifdef Q_OS_MACOS // Always show the mainwindow on startup for macOS
show();
#else
BehaviourSettingsPage::StartupBehaviour startupbehaviour = BehaviourSettingsPage::StartupBehaviour::Remember;
{
QSettings s;
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
startupbehaviour = static_cast<BehaviourSettingsPage::StartupBehaviour>(s.value("startupbehaviour", static_cast<int>(BehaviourSettingsPage::StartupBehaviour::Remember)).toInt());
s.endGroup();
}
2023-02-18 14:09:27 +01:00
switch (startupbehaviour) {
case BehaviourSettingsPage::StartupBehaviour::Show:
2020-07-16 00:06:51 +02:00
show();
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::StartupBehaviour::ShowMaximized:
2020-07-16 00:06:51 +02:00
setWindowState(windowState() | Qt::WindowMaximized);
show();
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::StartupBehaviour::ShowMinimized:
2020-07-16 00:06:51 +02:00
setWindowState(windowState() | Qt::WindowMinimized);
show();
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::StartupBehaviour::Hide:
if (tray_icon_->IsSystemTrayAvailable() && tray_icon_->isVisible()) {
break;
2020-07-16 00:06:51 +02:00
}
2022-07-26 20:37:06 +02:00
[[fallthrough]];
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::StartupBehaviour::Remember:
2020-07-16 00:06:51 +02:00
default: {
was_maximized_ = settings_.value("maximized", true).toBool();
if (was_maximized_) setWindowState(windowState() | Qt::WindowMaximized);
was_minimized_ = settings_.value("minimized", false).toBool();
if (was_minimized_) setWindowState(windowState() | Qt::WindowMinimized);
if (!tray_icon_->IsSystemTrayAvailable() || !tray_icon_->isVisible()) {
hidden_ = false;
2020-07-16 00:06:51 +02:00
settings_.setValue("hidden", false);
show();
2020-07-16 00:06:51 +02:00
}
else {
hidden_ = settings_.value("hidden", false).toBool();
2022-05-21 19:12:22 +02:00
if (!hidden_) {
show();
}
2020-07-16 00:06:51 +02:00
}
break;
}
}
2018-02-27 18:06:05 +01:00
#endif
bool show_sidebar = settings_.value("show_sidebar", true).toBool();
ui_->sidebar_layout->setVisible(show_sidebar);
ui_->action_toggle_show_sidebar->setChecked(show_sidebar);
2018-02-27 18:06:05 +01:00
QShortcut *close_window_shortcut = new QShortcut(this);
2020-09-04 20:43:02 +02:00
close_window_shortcut->setKey(Qt::CTRL | Qt::Key_W);
2021-01-26 16:48:04 +01:00
QObject::connect(close_window_shortcut, &QShortcut::activated, this, &MainWindow::ToggleHide);
2018-02-27 18:06:05 +01:00
QAction *action_focus_search = new QAction(this);
action_focus_search->setShortcuts(QList<QKeySequence>() << QKeySequence("Ctrl+F"));
addAction(action_focus_search);
QObject::connect(action_focus_search, &QAction::triggered, this, &MainWindow::FocusSearchField);
2018-02-27 18:06:05 +01:00
CheckFullRescanRevisions();
CommandlineOptionsReceived(options);
2019-05-02 11:31:31 +02:00
if (!options.contains_play_options()) {
LoadPlaybackStatus();
}
if (app_->scrobbler()->enabled() && !app_->scrobbler()->offline()) {
app_->scrobbler()->Submit();
}
2018-02-27 18:06:05 +01:00
#ifdef HAVE_QTSPARKLE
QUrl sparkle_url(QTSPARKLE_URL);
if (!sparkle_url.isEmpty()) {
qLog(Debug) << "Creating Qt Sparkle updater";
qtsparkle::Updater *updater = new qtsparkle::Updater(sparkle_url, this);
updater->SetVersion(STRAWBERRY_VERSION_PACKAGE);
2021-01-26 16:48:04 +01:00
QObject::connect(check_updates, &QAction::triggered, updater, &qtsparkle::Updater::CheckNow);
}
#endif
2020-10-15 21:47:52 +02:00
#ifdef Q_OS_LINUX
if (!Utilities::GetEnv("SNAP").isEmpty() && !Utilities::GetEnv("SNAP_NAME").isEmpty()) {
QSettings s;
2020-10-15 21:47:52 +02:00
s.beginGroup(kSettingsGroup);
2023-04-18 17:44:42 +02:00
const bool ignore_snap = s.value("ignore_snap", false).toBool();
s.endGroup();
if (!ignore_snap) {
SnapDialog *snap_dialog = new SnapDialog(this);
2020-10-15 21:47:52 +02:00
snap_dialog->setAttribute(Qt::WA_DeleteOnClose);
snap_dialog->show();
}
}
#endif
#if defined(Q_OS_MACOS)
2023-03-07 23:04:00 +01:00
if (Utilities::ProcessTranslated()) {
QSettings s;
s.beginGroup(kSettingsGroup);
const bool ignore_rosetta = s.value("ignore_rosetta", false).toBool();
s.endGroup();
if (!ignore_rosetta) {
MessageDialog *rosetta_message = new MessageDialog(this);
rosetta_message->set_settings_group(kSettingsGroup);
rosetta_message->set_do_not_show_message_again("ignore_rosetta");
rosetta_message->setAttribute(Qt::WA_DeleteOnClose);
2023-09-24 15:08:57 +02:00
rosetta_message->ShowMessage(tr("Strawberry running under Rosetta"), tr("You are running Strawberry under Rosetta. Running Strawberry under Rosetta is unsupported and known to have issues. You should download Strawberry for the correct CPU architecture from %1").arg("<a href=\"https://downloads.strawberrymusicplayer.org/\">downloads.strawberrymusicplayer.org</a>"), IconLoader::Load("dialog-warning"));
}
}
#endif
2023-09-24 15:09:20 +02:00
{
QSettings s;
s.beginGroup(kSettingsGroup);
const QString do_not_show_sponsor_message_key = QString("do_not_show_sponsor_message");
const bool do_not_show_sponsor_message = s.value(do_not_show_sponsor_message_key, false).toBool();
s.endGroup();
if (!do_not_show_sponsor_message) {
MessageDialog *sponsor_message = new MessageDialog(this);
sponsor_message->set_settings_group(kSettingsGroup);
sponsor_message->set_do_not_show_message_again(do_not_show_sponsor_message_key);
sponsor_message->setAttribute(Qt::WA_DeleteOnClose);
sponsor_message->ShowMessage(tr("Sponsoring Strawberry"), tr("Strawberry is free and open source software. If you like Strawberry, please consider sponsoring the project. For more information about sponsorship see our website %1").arg("<a href= \"https://www.strawberrymusicplayer.org/\">www.strawberrymusicplayer.org</a>"), IconLoader::Load("dialog-information"));
}
}
qLog(Debug) << "Started" << QThread::currentThread();
initialized_ = true;
2018-02-27 18:06:05 +01:00
}
MainWindow::~MainWindow() {
delete ui_;
}
void MainWindow::ReloadSettings() {
QSettings s;
2018-02-27 18:06:05 +01:00
2023-08-27 00:09:49 +02:00
#ifdef Q_OS_MACOS
constexpr bool keeprunning_available = true;
#else
const bool systemtray_available = tray_icon_->IsSystemTrayAvailable();
const bool keeprunning_available = systemtray_available;
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
2023-08-27 00:09:49 +02:00
const bool showtrayicon = s.value("showtrayicon", systemtray_available).toBool();
s.endGroup();
2023-08-27 00:09:49 +02:00
if (systemtray_available) {
2021-05-20 21:40:08 +02:00
tray_icon_->setVisible(showtrayicon);
}
2023-08-27 00:09:49 +02:00
if ((!showtrayicon || !systemtray_available) && !isVisible()) {
2021-05-20 21:40:08 +02:00
show();
}
2018-02-27 18:06:05 +01:00
#endif
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
2023-08-27 00:09:49 +02:00
keep_running_ = keeprunning_available && s.value("keeprunning", false).toBool();
playing_widget_ = s.value("playing_widget", true).toBool();
bool trayicon_progress = s.value("trayicon_progress", false).toBool();
2019-03-09 17:20:07 +01:00
if (playing_widget_ != ui_->widget_playing->IsEnabled()) TabSwitched();
2023-02-18 14:09:27 +01:00
doubleclick_addmode_ = static_cast<BehaviourSettingsPage::AddBehaviour>(s.value("doubleclick_addmode", static_cast<int>(BehaviourSettingsPage::AddBehaviour::Append)).toInt());
doubleclick_playmode_ = static_cast<BehaviourSettingsPage::PlayBehaviour>(s.value("doubleclick_playmode", static_cast<int>(BehaviourSettingsPage::PlayBehaviour::Never)).toInt());
doubleclick_playlist_addmode_ = static_cast<BehaviourSettingsPage::PlaylistAddBehaviour>(s.value("doubleclick_playlist_addmode", static_cast<int>(BehaviourSettingsPage::PlayBehaviour::Never)).toInt());
menu_playmode_ = static_cast<BehaviourSettingsPage::PlayBehaviour>(s.value("menu_playmode", static_cast<int>(BehaviourSettingsPage::PlayBehaviour::Never)).toInt());
s.endGroup();
s.beginGroup(AppearanceSettingsPage::kSettingsGroup);
int iconsize = s.value(AppearanceSettingsPage::kIconSizePlayControlButtons, 32).toInt();
s.endGroup();
2021-05-20 21:40:08 +02:00
tray_icon_->SetTrayiconProgress(trayicon_progress);
ui_->back_button->setIconSize(QSize(iconsize, iconsize));
ui_->pause_play_button->setIconSize(QSize(iconsize, iconsize));
ui_->stop_button->setIconSize(QSize(iconsize, iconsize));
ui_->forward_button->setIconSize(QSize(iconsize, iconsize));
ui_->button_love->setIconSize(QSize(iconsize, iconsize));
s.beginGroup(BackendSettingsPage::kSettingsGroup);
bool volume_control = s.value("volume_control", true).toBool();
s.endGroup();
2019-03-09 16:48:45 +01:00
if (volume_control != ui_->volume->isEnabled()) {
ui_->volume->SetEnabled(volume_control);
if (volume_control) {
if (!ui_->action_mute->isVisible()) ui_->action_mute->setVisible(true);
2021-05-20 21:40:08 +02:00
if (!tray_icon_->MuteEnabled()) tray_icon_->SetMuteEnabled(true);
2019-03-09 16:48:45 +01:00
}
else {
if (ui_->action_mute->isVisible()) ui_->action_mute->setVisible(false);
2021-05-20 21:40:08 +02:00
if (tray_icon_->MuteEnabled()) tray_icon_->SetMuteEnabled(false);
2019-03-09 16:48:45 +01:00
}
}
s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
delete_files_ = s.value("delete_files", false).toBool();
s.endGroup();
2020-08-09 01:37:00 +02:00
osd_->ReloadSettings();
album_cover_choice_controller_->search_cover_auto_action()->setChecked(settings_.value("search_for_cover_auto", true).toBool());
2019-06-17 23:54:24 +02:00
#ifdef HAVE_SUBSONIC
s.beginGroup(SubsonicSettingsPage::kSettingsGroup);
bool enable_subsonic = s.value("enabled", false).toBool();
s.endGroup();
2021-08-23 21:21:08 +02:00
if (enable_subsonic) {
2019-06-17 23:54:24 +02:00
ui_->tabs->EnableTab(subsonic_view_);
2021-08-23 21:21:08 +02:00
}
else {
2019-06-17 23:54:24 +02:00
ui_->tabs->DisableTab(subsonic_view_);
2021-08-23 21:21:08 +02:00
}
2019-06-17 23:54:24 +02:00
#endif
2020-04-13 19:04:06 +02:00
#ifdef HAVE_TIDAL
s.beginGroup(TidalSettingsPage::kSettingsGroup);
bool enable_tidal = s.value("enabled", false).toBool();
s.endGroup();
2021-08-23 21:21:08 +02:00
if (enable_tidal) {
2020-04-13 19:04:06 +02:00
ui_->tabs->EnableTab(tidal_view_);
2021-08-23 21:21:08 +02:00
}
else {
2020-04-13 19:04:06 +02:00
ui_->tabs->DisableTab(tidal_view_);
2021-08-23 21:21:08 +02:00
}
2020-04-13 19:04:06 +02:00
#endif
#ifdef HAVE_QOBUZ
s.beginGroup(QobuzSettingsPage::kSettingsGroup);
bool enable_qobuz = s.value("enabled", false).toBool();
s.endGroup();
2021-08-23 21:21:08 +02:00
if (enable_qobuz) {
ui_->tabs->EnableTab(qobuz_view_);
2021-08-23 21:21:08 +02:00
}
else {
ui_->tabs->DisableTab(qobuz_view_);
2021-08-23 21:21:08 +02:00
}
#endif
ui_->tabs->ReloadSettings();
2018-02-27 18:06:05 +01:00
}
void MainWindow::ReloadAllSettings() {
ReloadSettings();
// Other settings
app_->ReloadSettings();
app_->collection()->ReloadSettings();
app_->player()->ReloadSettings();
collection_view_->ReloadSettings();
ui_->playlist->view()->ReloadSettings();
app_->playlist_manager()->playlist_container()->ReloadSettings();
2023-05-14 11:34:55 +02:00
app_->current_albumcover_loader()->ReloadSettingsAsync();
album_cover_choice_controller_->ReloadSettings();
context_view_->ReloadSettings();
file_view_->ReloadSettings();
queue_view_->ReloadSettings();
playlist_list_->ReloadSettings();
smartplaylists_view_->ReloadSettings();
2021-07-11 01:02:53 +02:00
radio_view_->ReloadSettings();
app_->internet_services()->ReloadSettings();
app_->radio_services()->ReloadSettings();
2020-05-09 01:48:08 +02:00
app_->cover_providers()->ReloadSettings();
app_->lyrics_providers()->ReloadSettings();
2021-01-26 22:34:31 +01:00
#ifdef HAVE_MOODBAR
app_->moodbar_controller()->ReloadSettings();
#endif
2019-06-17 23:54:24 +02:00
#ifdef HAVE_SUBSONIC
subsonic_view_->ReloadSettings();
#endif
2020-04-13 19:04:06 +02:00
#ifdef HAVE_TIDAL
tidal_view_->ReloadSettings();
#endif
#ifdef HAVE_QOBUZ
qobuz_view_->ReloadSettings();
#endif
2018-02-27 18:06:05 +01:00
}
void MainWindow::RefreshStyleSheet() {
QString contents(styleSheet());
setStyleSheet("");
setStyleSheet(contents);
2018-02-27 18:06:05 +01:00
}
2018-10-20 22:16:22 +02:00
void MainWindow::SaveSettings() {
SaveGeometry();
SavePlaybackStatus();
app_->player()->SaveVolume();
ui_->tabs->SaveSettings(kSettingsGroup);
ui_->playlist->view()->SaveSettings();
app_->scrobbler()->WriteCache();
settings_.setValue("show_sidebar", ui_->action_toggle_show_sidebar->isChecked());
settings_.setValue("search_for_cover_auto", album_cover_choice_controller_->search_cover_auto_action()->isChecked());
}
void MainWindow::Exit() {
2019-07-24 23:29:09 +02:00
++exit_count_;
SaveSettings();
// Make sure Settings dialog is destroyed first.
settings_dialog_.reset();
2019-07-24 23:29:09 +02:00
if (exit_count_ > 1) {
exit_ = true;
QCoreApplication::quit();
2019-07-24 23:29:09 +02:00
}
else {
if (app_->player()->engine()->is_fadeout_enabled()) {
// To shut down the application when fadeout will be finished
QObject::connect(&*app_->player()->engine(), &EngineBase::FadeoutFinishedSignal, this, &MainWindow::DoExit);
2023-04-22 19:13:42 +02:00
if (app_->player()->GetState() == EngineBase::State::Playing) {
2019-07-24 23:29:09 +02:00
app_->player()->Stop();
2022-05-21 19:12:22 +02:00
ignore_close_ = true;
close();
if (tray_icon_->IsSystemTrayAvailable()) {
2021-05-20 21:40:08 +02:00
tray_icon_->setVisible(false);
}
2021-07-11 09:49:38 +02:00
return; // Don't quit the application now: wait for the fadeout finished signal
2019-07-24 23:29:09 +02:00
}
}
#ifdef HAVE_DBUS
UpdateTaskbarProgress(false, 0, 0);
#endif
2019-07-24 23:29:09 +02:00
DoExit();
}
}
void MainWindow::DoExit() {
2021-01-26 16:48:04 +01:00
QObject::connect(app_, &Application::ExitFinished, this, &MainWindow::ExitFinished);
app_->Exit();
}
void MainWindow::ExitFinished() {
2021-04-16 18:34:38 +02:00
exit_ = true;
QCoreApplication::quit();
}
2023-04-22 19:13:42 +02:00
void MainWindow::EngineChanged(const EngineBase::Type enginetype) {
2023-04-22 19:13:42 +02:00
ui_->action_equalizer->setEnabled(enginetype == EngineBase::Type::GStreamer);
#if defined(HAVE_AUDIOCD) && !defined(Q_OS_WIN)
2023-04-22 19:13:42 +02:00
ui_->action_open_cd->setEnabled(enginetype == EngineBase::Type::GStreamer);
#else
2020-04-08 00:56:19 +02:00
ui_->action_open_cd->setEnabled(false);
2020-04-08 01:00:21 +02:00
ui_->action_open_cd->setVisible(false);
2020-04-08 00:56:19 +02:00
#endif
}
2018-02-27 18:06:05 +01:00
void MainWindow::MediaStopped() {
2018-02-27 18:06:05 +01:00
setWindowTitle("Strawberry Music Player");
ui_->action_stop->setEnabled(false);
ui_->action_stop_after_this_track->setEnabled(false);
ui_->action_play_pause->setIcon(IconLoader::Load("media-playback-start"));
2018-02-27 18:06:05 +01:00
ui_->action_play_pause->setText(tr("Play"));
ui_->action_play_pause->setEnabled(true);
2019-06-12 00:38:52 +02:00
ui_->action_love->setEnabled(false);
ui_->button_love->setEnabled(false);
2021-05-20 21:40:08 +02:00
tray_icon_->LoveStateChanged(false);
2019-06-12 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
track_position_timer_->stop();
track_slider_timer_->stop();
ui_->track_slider->SetStopped();
2021-05-20 21:40:08 +02:00
tray_icon_->SetProgress(0);
tray_icon_->SetStopped();
2018-02-27 18:06:05 +01:00
#ifdef HAVE_DBUS
UpdateTaskbarProgress(false, 0, 0);
#endif
2018-09-22 23:13:56 +02:00
song_playing_ = Song();
song_ = Song();
album_cover_ = AlbumCoverImageResult();
2019-06-12 00:38:52 +02:00
app_->scrobbler()->ClearPlaying();
2018-02-27 18:06:05 +01:00
}
void MainWindow::MediaPaused() {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
ui_->action_stop->setEnabled(true);
ui_->action_stop_after_this_track->setEnabled(true);
ui_->action_play_pause->setIcon(IconLoader::Load("media-playback-start"));
2018-02-27 18:06:05 +01:00
ui_->action_play_pause->setText(tr("Play"));
ui_->action_play_pause->setEnabled(true);
track_position_timer_->stop();
track_slider_timer_->stop();
2021-05-20 21:40:08 +02:00
tray_icon_->SetPaused();
2018-02-27 18:06:05 +01:00
}
void MainWindow::MediaPlaying() {
2018-08-09 18:10:03 +02:00
2018-02-27 18:06:05 +01:00
ui_->action_stop->setEnabled(true);
ui_->action_stop_after_this_track->setEnabled(true);
ui_->action_play_pause->setIcon(IconLoader::Load("media-playback-pause"));
2018-02-27 18:06:05 +01:00
ui_->action_play_pause->setText(tr("Pause"));
bool enable_play_pause(false);
bool can_seek(false);
PlaylistItemPtr item(app_->player()->GetCurrentItem());
if (item) {
2023-02-18 14:09:27 +01:00
enable_play_pause = !(item->options() & PlaylistItem::Option::PauseDisabled);
can_seek = !(item->options() & PlaylistItem::Option::SeekDisabled);
}
2018-02-27 18:06:05 +01:00
ui_->action_play_pause->setEnabled(enable_play_pause);
ui_->track_slider->SetCanSeek(can_seek);
2021-05-20 21:40:08 +02:00
tray_icon_->SetPlaying(enable_play_pause);
2018-02-27 18:06:05 +01:00
track_position_timer_->start();
track_slider_timer_->start();
UpdateTrackPosition();
2020-04-25 00:07:42 +02:00
}
void MainWindow::SendNowPlaying() {
// Send now playing to scrobble services
Playlist *playlist = app_->playlist_manager()->active();
if (app_->scrobbler()->enabled() && playlist && playlist->current_item() && playlist->current_item()->Metadata().is_metadata_good()) {
app_->scrobbler()->UpdateNowPlaying(playlist->current_item()->Metadata());
2019-06-12 00:38:52 +02:00
ui_->action_love->setEnabled(true);
ui_->button_love->setEnabled(true);
2021-05-20 21:40:08 +02:00
tray_icon_->LoveStateChanged(true);
}
2018-02-27 18:06:05 +01:00
}
2022-09-12 23:18:54 +02:00
void MainWindow::VolumeChanged(const uint volume) {
2021-06-22 13:54:58 +02:00
ui_->action_mute->setChecked(volume == 0);
tray_icon_->MuteButtonStateChanged(volume == 0);
2018-02-27 18:06:05 +01:00
}
void MainWindow::SongChanged(const Song &song) {
qLog(Debug) << "Song changed to" << song.artist() << song.album() << song.PrettyTitle();
2020-10-01 20:09:36 +02:00
song_playing_ = song;
song_ = song;
setWindowTitle(song.PrettyTitleWithArtist());
2021-05-20 21:40:08 +02:00
tray_icon_->SetProgress(0);
2018-02-27 18:06:05 +01:00
#ifdef HAVE_DBUS
UpdateTaskbarProgress(false, 0, 0);
#endif
SendNowPlaying();
const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty();
2023-05-14 11:34:55 +02:00
album_cover_choice_controller_->show_cover_action()->setEnabled(song.has_valid_art() && !song.art_unset());
album_cover_choice_controller_->cover_to_file_action()->setEnabled(song.has_valid_art() && !song.art_unset());
album_cover_choice_controller_->cover_from_file_action()->setEnabled(enable_change_art);
album_cover_choice_controller_->cover_from_url_action()->setEnabled(enable_change_art);
album_cover_choice_controller_->search_for_cover_action()->setEnabled(app_->cover_providers()->HasAnyProviders() && enable_change_art);
2023-05-14 11:34:55 +02:00
album_cover_choice_controller_->unset_cover_action()->setEnabled(enable_change_art && !song.art_unset());
album_cover_choice_controller_->clear_cover_action()->setEnabled(enable_change_art && !song.art_manual().isEmpty());
2023-05-14 11:34:55 +02:00
album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && (song.art_embedded() || !song.art_automatic().isEmpty() || !song.art_manual().isEmpty()));
2018-02-27 18:06:05 +01:00
}
void MainWindow::TrackSkipped(PlaylistItemPtr item) {
2018-02-27 18:06:05 +01:00
// If it was a collection item then we have to increment its skipped count in the database.
if (item && item->IsLocalCollectionItem() && item->Metadata().id() != -1) {
Song song = item->Metadata();
const qint64 position = app_->player()->engine()->position_nanosec();
const qint64 length = app_->player()->engine()->length_nanosec();
2021-10-11 22:28:28 +02:00
const float percentage = (length == 0 ? 1 : static_cast<float>(position) / static_cast<float>(length));
2018-02-27 18:06:05 +01:00
const qint64 seconds_left = (length - position) / kNsecPerSec;
const qint64 seconds_total = length / kNsecPerSec;
2021-10-30 02:21:29 +02:00
if (((0.05 * static_cast<double>(seconds_total) > 60.0 && percentage < 0.98) || percentage < 0.95) && seconds_left > 5) { // Never count the skip if under 5 seconds left
2018-02-27 18:06:05 +01:00
app_->collection_backend()->IncrementSkipCountAsync(song.id(), percentage);
}
}
2018-02-27 18:06:05 +01:00
}
void MainWindow::TabSwitched() {
2018-10-02 00:38:52 +02:00
if (playing_widget_ && ui_->action_toggle_show_sidebar->isChecked() && (ui_->tabs->currentIndex() != ui_->tabs->IndexOfTab(context_view_) || !context_view_->album_enabled())) {
ui_->widget_playing->SetEnabled();
2019-03-09 17:20:07 +01:00
}
else {
ui_->widget_playing->SetDisabled();
}
2018-02-27 18:06:05 +01:00
}
void MainWindow::ToggleSidebar(const bool checked) {
ui_->sidebar_layout->setVisible(checked);
TabSwitched();
settings_.setValue("show_sidebar", checked);
}
void MainWindow::ToggleSearchCoverAuto(const bool checked) {
settings_.setValue("search_for_cover_auto", checked);
}
2018-02-27 18:06:05 +01:00
void MainWindow::SaveGeometry() {
if (!initialized_) return;
settings_.setValue("maximized", isMaximized());
settings_.setValue("minimized", isMinimized());
settings_.setValue("hidden", hidden_);
settings_.setValue("geometry", saveGeometry());
2018-02-27 18:06:05 +01:00
settings_.setValue("splitter_state", ui_->splitter->saveState());
}
void MainWindow::SavePlaybackStatus() {
2018-10-02 00:38:52 +02:00
2019-05-02 11:31:31 +02:00
QSettings s;
2018-02-27 18:06:05 +01:00
2019-05-02 11:31:31 +02:00
s.beginGroup(Player::kSettingsGroup);
2023-02-18 14:09:27 +01:00
s.setValue("playback_state", static_cast<int>(app_->player()->GetState()));
2023-04-22 19:13:42 +02:00
if (app_->player()->GetState() == EngineBase::State::Playing || app_->player()->GetState() == EngineBase::State::Paused) {
s.setValue("playback_playlist", app_->playlist_manager()->active()->id());
2019-05-02 11:31:31 +02:00
s.setValue("playback_position", app_->player()->engine()->position_nanosec() / kNsecPerSec);
2018-02-27 18:06:05 +01:00
}
else {
s.setValue("playback_playlist", -1);
2019-05-02 11:31:31 +02:00
s.setValue("playback_position", 0);
2018-02-27 18:06:05 +01:00
}
2018-10-02 00:38:52 +02:00
2019-05-02 11:31:31 +02:00
s.endGroup();
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::LoadPlaybackStatus() {
2018-10-02 00:38:52 +02:00
2019-05-02 11:31:31 +02:00
QSettings s;
2018-02-27 18:06:05 +01:00
2019-05-02 11:31:31 +02:00
s.beginGroup(BehaviourSettingsPage::kSettingsGroup);
2023-02-18 14:09:27 +01:00
const bool resume_playback = s.value("resumeplayback", false).toBool();
2019-05-02 11:31:31 +02:00
s.endGroup();
2018-02-27 18:06:05 +01:00
2019-05-02 11:31:31 +02:00
s.beginGroup(Player::kSettingsGroup);
2023-04-22 19:13:42 +02:00
const EngineBase::State playback_state = static_cast<EngineBase::State>(s.value("playback_state", static_cast<int>(EngineBase::State::Empty)).toInt());
2019-05-02 11:31:31 +02:00
s.endGroup();
2018-10-02 00:38:52 +02:00
2023-04-22 19:13:42 +02:00
if (resume_playback && playback_state != EngineBase::State::Empty && playback_state != EngineBase::State::Idle) {
SharedPtr<QMetaObject::Connection> connection = make_shared<QMetaObject::Connection>();
*connection = QObject::connect(&*app_->playlist_manager(), &PlaylistManager::AllPlaylistsLoaded, this, [this, connection]() {
QObject::disconnect(*connection);
2021-08-25 02:57:09 +02:00
QTimer::singleShot(400ms, this, &MainWindow::ResumePlayback);
});
2018-02-27 18:06:05 +01:00
}
}
void MainWindow::ResumePlayback() {
qLog(Debug) << "Resuming playback";
QSettings s;
s.beginGroup(Player::kSettingsGroup);
2023-04-22 19:13:42 +02:00
const EngineBase::State playback_state = static_cast<EngineBase::State>(s.value("playback_state", static_cast<int>(EngineBase::State::Empty)).toInt());
int playback_playlist = s.value("playback_playlist", -1).toInt();
int playback_position = s.value("playback_position", 0).toInt();
s.endGroup();
if (playback_playlist == app_->playlist_manager()->current()->id()) {
// Set active to current to resume playback on correct playlist.
app_->playlist_manager()->SetActiveToCurrent();
2023-04-22 19:13:42 +02:00
if (playback_state == EngineBase::State::Paused) {
SharedPtr<QMetaObject::Connection> connection = make_shared<QMetaObject::Connection>();
*connection = QObject::connect(&*app_->player(), &Player::Playing, &*app_->player(), [this, connection]() {
QObject::disconnect(*connection);
QTimer::singleShot(300, &*app_->player(), &Player::PlayPauseHelper);
});
}
app_->player()->Play(playback_position * kNsecPerSec);
2018-02-27 18:06:05 +01:00
}
// Reset saved playback status so we don't resume again from the same position.
s.beginGroup(Player::kSettingsGroup);
2023-04-22 19:13:42 +02:00
s.setValue("playback_state", static_cast<int>(EngineBase::State::Empty));
s.setValue("playback_playlist", -1);
s.setValue("playback_position", 0);
s.endGroup();
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlayIndex(const QModelIndex &idx, Playlist::AutoScroll autoscroll) {
2018-10-02 00:38:52 +02:00
2020-08-23 19:17:50 +02:00
if (!idx.isValid()) return;
2018-02-27 18:06:05 +01:00
2020-08-23 19:17:50 +02:00
int row = idx.row();
2022-08-09 17:23:46 +02:00
if (idx.model() == app_->playlist_manager()->current()->filter()) {
// The index was in the proxy model (might've been filtered), so we need to get the actual row in the source model.
2022-08-09 17:23:46 +02:00
row = app_->playlist_manager()->current()->filter()->mapToSource(idx).row();
2018-02-27 18:06:05 +01:00
}
app_->playlist_manager()->SetActiveToCurrent();
2023-04-22 19:13:42 +02:00
app_->player()->PlayAt(row, 0, EngineBase::TrackChangeType::Manual, autoscroll, true);
2018-02-27 18:06:05 +01:00
}
2020-08-23 19:17:50 +02:00
void MainWindow::PlaylistDoubleClick(const QModelIndex &idx) {
2020-08-23 19:17:50 +02:00
if (!idx.isValid()) return;
2018-02-27 18:06:05 +01:00
QModelIndex source_idx = idx;
2022-08-09 17:23:46 +02:00
if (idx.model() == app_->playlist_manager()->current()->filter()) {
// The index was in the proxy model (might've been filtered), so we need to get the actual row in the source model.
2022-08-09 17:23:46 +02:00
source_idx = app_->playlist_manager()->current()->filter()->mapToSource(idx);
2018-02-27 18:06:05 +01:00
}
switch (doubleclick_playlist_addmode_) {
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::PlaylistAddBehaviour::Play:
2018-02-27 18:06:05 +01:00
app_->playlist_manager()->SetActiveToCurrent();
2023-04-22 19:13:42 +02:00
app_->player()->PlayAt(source_idx.row(), 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Never, true, true);
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::PlaylistAddBehaviour::Enqueue:
app_->playlist_manager()->current()->queue()->ToggleTracks(QModelIndexList() << source_idx);
2023-04-22 19:13:42 +02:00
if (app_->player()->GetState() != EngineBase::State::Playing) {
app_->playlist_manager()->SetActiveToCurrent();
2023-04-22 19:13:42 +02:00
app_->player()->PlayAt(app_->playlist_manager()->current()->queue()->TakeNext(), 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Never, true);
2018-02-27 18:06:05 +01:00
}
break;
}
2018-02-27 18:06:05 +01:00
}
2020-02-22 00:09:45 +01:00
void MainWindow::VolumeWheelEvent(const int delta) {
2018-02-27 18:06:05 +01:00
ui_->volume->setValue(ui_->volume->value() + delta / 30);
}
void MainWindow::ToggleShowHide() {
2018-10-02 00:38:52 +02:00
if (hidden_) {
2018-02-27 18:06:05 +01:00
SetHiddenInTray(false);
}
else if (isActiveWindow()) {
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
SetHiddenInTray(true);
}
else if (isMinimized()) {
setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
SetHiddenInTray(false);
}
else if (!isVisible()) {
show();
activateWindow();
}
else {
// Window is not hidden but does not have focus; bring it to front.
activateWindow();
raise();
}
2018-02-27 18:06:05 +01:00
}
2021-01-26 16:48:04 +01:00
void MainWindow::ToggleHide() {
if (!hidden_) SetHiddenInTray(true);
}
2018-02-27 18:06:05 +01:00
void MainWindow::StopAfterCurrent() {
app_->playlist_manager()->current()->StopAfter(app_->playlist_manager()->current()->current_row());
emit StopAfterToggled(app_->playlist_manager()->active()->stop_after_current());
}
2020-10-05 19:08:09 +02:00
void MainWindow::showEvent(QShowEvent *e) {
hidden_ = false;
QMainWindow::showEvent(e);
}
void MainWindow::closeEvent(QCloseEvent *e) {
2018-02-27 18:06:05 +01:00
2022-05-21 19:12:22 +02:00
if (ignore_close_) {
ignore_close_ = false;
QMainWindow::closeEvent(e);
return;
}
if (!exit_) {
if (!hidden_ && keep_running_ && tray_icon_->IsSystemTrayAvailable()) {
SetHiddenInTray(true);
}
else {
Exit();
}
2018-02-27 18:06:05 +01:00
}
2019-07-24 23:29:09 +02:00
QMainWindow::closeEvent(e);
2018-02-27 18:06:05 +01:00
}
2020-02-22 00:09:45 +01:00
void MainWindow::SetHiddenInTray(const bool hidden) {
2018-02-27 18:06:05 +01:00
hidden_ = hidden;
settings_.setValue("hidden", hidden_);
2018-02-27 18:06:05 +01:00
// Some window managers don't remember maximized state between calls to hide() and show(), so we have to remember it ourself.
2018-02-27 18:06:05 +01:00
if (hidden) {
was_maximized_ = isMaximized();
was_minimized_ = isMinimized();
2022-05-21 19:12:22 +02:00
ignore_close_ = true;
close();
2018-02-27 18:06:05 +01:00
}
else {
2021-07-11 09:49:38 +02:00
if (was_minimized_) {
showMinimized();
}
else if (was_maximized_) {
showMaximized();
}
else {
show();
}
2018-02-27 18:06:05 +01:00
}
2018-02-27 18:06:05 +01:00
}
void MainWindow::FilePathChanged(const QString &path) {
settings_.setValue("file_path", path);
}
2021-03-21 18:53:02 +01:00
void MainWindow::Seeked(const qint64 microseconds) {
2018-02-27 18:06:05 +01:00
2021-03-21 18:53:02 +01:00
const qint64 position = microseconds / kUsecPerSec;
const qint64 length = app_->player()->GetCurrentItem()->Metadata().length_nanosec() / kNsecPerSec;
2021-10-30 02:21:29 +02:00
tray_icon_->SetProgress(static_cast<int>(static_cast<double>(position) / static_cast<double>(length) * 100.0));
2018-02-27 18:06:05 +01:00
#ifdef HAVE_DBUS
UpdateTaskbarProgress(true, position, length);
#endif
2018-02-27 18:06:05 +01:00
}
void MainWindow::UpdateTrackPosition() {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
PlaylistItemPtr item(app_->player()->GetCurrentItem());
if (!item) return;
2018-02-27 18:06:05 +01:00
2021-03-21 18:53:02 +01:00
const qint64 length = (item->Metadata().length_nanosec() / kNsecPerSec);
if (length <= 0) return;
2021-10-30 02:21:29 +02:00
const int position = std::floor(static_cast<float>(app_->player()->engine()->position_nanosec()) / static_cast<float>(kNsecPerSec) + 0.5);
2018-02-27 18:06:05 +01:00
// Update the tray icon every 10 seconds
2021-10-30 02:21:29 +02:00
if (position % 10 == 0) tray_icon_->SetProgress(static_cast<int>(static_cast<double>(position) / static_cast<double>(length) * 100.0));
#ifdef HAVE_DBUS
UpdateTaskbarProgress(true, position, length);
#endif
// Send Scrobble
if (app_->scrobbler()->enabled() && item->Metadata().is_metadata_good()) {
Playlist *playlist = app_->playlist_manager()->active();
if (playlist && !playlist->scrobbled()) {
2021-03-21 18:53:02 +01:00
const qint64 scrobble_point = (playlist->scrobble_point_nanosec() / kNsecPerSec);
if (position >= scrobble_point) {
app_->scrobbler()->Scrobble(item->Metadata(), scrobble_point);
playlist->set_scrobbled(true);
}
}
}
2018-02-27 18:06:05 +01:00
}
void MainWindow::UpdateTrackSliderPosition() {
2018-02-27 18:06:05 +01:00
PlaylistItemPtr item(app_->player()->GetCurrentItem());
2021-10-11 22:28:28 +02:00
const int slider_position = std::floor(static_cast<float>(app_->player()->engine()->position_nanosec()) / kNsecPerMsec);
const int slider_length = static_cast<int>(app_->player()->engine()->length_nanosec() / kNsecPerMsec);
2018-02-27 18:06:05 +01:00
// Update the slider
ui_->track_slider->SetValue(slider_position, slider_length);
2018-02-27 18:06:05 +01:00
}
#ifdef HAVE_DBUS
void MainWindow::UpdateTaskbarProgress(const bool visible, const double position, const double length) {
QVariantMap map;
QDBusMessage msg = QDBusMessage::createSignal(QStringLiteral("/org/strawberrymusicplayer/strawberry"), QStringLiteral("com.canonical.Unity.LauncherEntry"), QStringLiteral("Update"));
map.insert(QStringLiteral("progress-visible"), visible);
map.insert(QStringLiteral("progress"), position / length);
msg << QString("application://org.strawberrymusicplayer.strawberry.desktop") << map;
QDBusConnection::sessionBus().send(msg);
}
#endif
2021-06-22 13:41:38 +02:00
void MainWindow::ApplyAddBehaviour(const BehaviourSettingsPage::AddBehaviour b, MimeData *mimedata) {
2018-02-27 18:06:05 +01:00
switch (b) {
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::AddBehaviour::Append:
2020-04-23 21:08:28 +02:00
mimedata->clear_first_ = false;
mimedata->enqueue_now_ = false;
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::AddBehaviour::Enqueue:
2020-04-23 21:08:28 +02:00
mimedata->clear_first_ = false;
mimedata->enqueue_now_ = true;
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::AddBehaviour::Load:
2020-04-23 21:08:28 +02:00
mimedata->clear_first_ = true;
mimedata->enqueue_now_ = false;
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::AddBehaviour::OpenInNew:
2020-04-23 21:08:28 +02:00
mimedata->open_in_new_playlist_ = true;
2018-02-27 18:06:05 +01:00
break;
}
}
2020-08-23 19:17:50 +02:00
void MainWindow::ApplyPlayBehaviour(const BehaviourSettingsPage::PlayBehaviour b, MimeData *mimedata) const {
2018-02-27 18:06:05 +01:00
switch (b) {
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::PlayBehaviour::Always:
2020-04-23 21:08:28 +02:00
mimedata->play_now_ = true;
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::PlayBehaviour::Never:
2020-04-23 21:08:28 +02:00
mimedata->play_now_ = false;
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case BehaviourSettingsPage::PlayBehaviour::IfStopped:
2023-04-22 19:13:42 +02:00
mimedata->play_now_ = !(app_->player()->GetState() == EngineBase::State::Playing);
2018-02-27 18:06:05 +01:00
break;
}
}
2020-04-23 21:08:28 +02:00
void MainWindow::AddToPlaylist(QMimeData *q_mimedata) {
2018-02-27 18:06:05 +01:00
2020-04-23 21:08:28 +02:00
if (!q_mimedata) return;
2018-02-27 18:06:05 +01:00
2020-04-23 21:08:28 +02:00
if (MimeData *mimedata = qobject_cast<MimeData*>(q_mimedata)) {
2018-02-27 18:06:05 +01:00
// Should we replace the flags with the user's preference?
2020-04-23 21:08:28 +02:00
if (mimedata->override_user_settings_) {
2018-02-27 18:06:05 +01:00
// Do nothing
}
2020-04-23 21:08:28 +02:00
else if (mimedata->from_doubleclick_) {
ApplyAddBehaviour(doubleclick_addmode_, mimedata);
ApplyPlayBehaviour(doubleclick_playmode_, mimedata);
2018-02-27 18:06:05 +01:00
}
else {
2020-04-23 21:08:28 +02:00
ApplyPlayBehaviour(menu_playmode_, mimedata);
2018-02-27 18:06:05 +01:00
}
// Should we create a new playlist for the songs?
2020-04-23 21:08:28 +02:00
if (mimedata->open_in_new_playlist_) {
app_->playlist_manager()->New(mimedata->get_name_for_new_playlist());
2018-02-27 18:06:05 +01:00
}
}
2020-04-23 21:08:28 +02:00
app_->playlist_manager()->current()->dropMimeData(q_mimedata, Qt::CopyAction, -1, 0, QModelIndex());
delete q_mimedata;
2018-02-27 18:06:05 +01:00
}
2021-01-26 16:48:04 +01:00
void MainWindow::AddToPlaylistFromAction(QAction *action) {
2018-10-02 00:38:52 +02:00
2020-02-22 00:09:45 +01:00
const int destination = action->data().toInt();
2023-02-18 14:09:27 +01:00
PlaylistItemPtrList items;
2020-02-22 00:09:45 +01:00
SongList songs;
2018-02-27 18:06:05 +01:00
// Get the selected playlist items
2020-02-22 15:31:25 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
items << item;
2018-02-27 18:06:05 +01:00
songs << item->Metadata();
}
// We're creating a new playlist
2018-02-27 18:06:05 +01:00
if (destination == -1) {
// Save the current playlist to reactivate it
2020-02-22 00:09:45 +01:00
const int current_id = app_->playlist_manager()->current_id();
// Get the name from selection
2018-02-27 18:06:05 +01:00
app_->playlist_manager()->New(app_->playlist_manager()->GetNameForNewPlaylist(songs));
if (app_->playlist_manager()->current()->id() != current_id) {
// I'm sure the new playlist was created and is selected, so I can just insert items
2018-02-27 18:06:05 +01:00
app_->playlist_manager()->current()->InsertItems(items);
// Set back the current playlist
2018-02-27 18:06:05 +01:00
app_->playlist_manager()->SetCurrentPlaylist(current_id);
}
}
else {
// We're inserting in a existing playlist
2018-02-27 18:06:05 +01:00
app_->playlist_manager()->playlist(destination)->InsertItems(items);
}
}
2019-07-26 22:46:04 +02:00
void MainWindow::PlaylistMenuHidden() {
playlist_queue_->setVisible(true);
playlist_queue_play_next_->setVisible(true);
playlist_skip_->setVisible(true);
}
2021-06-20 19:04:08 +02:00
void MainWindow::PlaylistRightClick(const QPoint global_pos, const QModelIndex &index) {
2018-02-27 18:06:05 +01:00
2020-02-22 15:31:25 +01:00
QModelIndex source_index = index;
2022-08-09 17:23:46 +02:00
if (index.model() == app_->playlist_manager()->current()->filter()) {
source_index = app_->playlist_manager()->current()->filter()->mapToSource(index);
2020-02-22 15:31:25 +01:00
}
2018-02-27 18:06:05 +01:00
playlist_menu_index_ = source_index;
// Is this song currently playing?
2023-04-22 19:13:42 +02:00
if (app_->playlist_manager()->current()->current_row() == source_index.row() && app_->player()->GetState() == EngineBase::State::Playing) {
2018-02-27 18:06:05 +01:00
playlist_play_pause_->setText(tr("Pause"));
playlist_play_pause_->setIcon(IconLoader::Load("media-playback-pause"));
2018-02-27 18:06:05 +01:00
}
else {
playlist_play_pause_->setText(tr("Play"));
playlist_play_pause_->setIcon(IconLoader::Load("media-playback-start"));
2018-02-27 18:06:05 +01:00
}
// Are we allowed to pause?
if (source_index.isValid()) {
2023-02-18 14:09:27 +01:00
playlist_play_pause_->setEnabled(app_->playlist_manager()->current()->current_row() != source_index.row() || !(app_->playlist_manager()->current()->item_at(source_index.row())->options() & PlaylistItem::Option::PauseDisabled));
2018-02-27 18:06:05 +01:00
}
else {
playlist_play_pause_->setEnabled(false);
}
playlist_stop_after_->setEnabled(source_index.isValid());
2018-02-27 18:06:05 +01:00
// Are any of the selected songs editable or queued?
2020-02-22 15:31:25 +01:00
QModelIndexList selection = ui_->playlist->view()->selectionModel()->selectedRows();
2018-02-27 18:06:05 +01:00
bool cue_selected = false;
2021-10-30 02:21:29 +02:00
qint64 selected = ui_->playlist->view()->selectionModel()->selectedRows().count();
2018-02-27 18:06:05 +01:00
int editable = 0;
int in_queue = 0;
int not_in_queue = 0;
int in_skipped = 0;
int not_in_skipped = 0;
int local_songs = 0;
2018-10-02 00:38:52 +02:00
2020-02-22 15:31:25 +01:00
for (const QModelIndex &idx : selection) {
2018-10-02 00:38:52 +02:00
2022-08-09 17:23:46 +02:00
const QModelIndex src_idx = app_->playlist_manager()->current()->filter()->mapToSource(idx);
2020-02-22 15:31:25 +01:00
if (!src_idx.isValid()) continue;
2018-02-27 18:06:05 +01:00
2020-02-22 15:31:25 +01:00
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(src_idx.row());
if (!item) continue;
2018-10-02 00:38:52 +02:00
if (item->Metadata().url().isLocalFile()) ++local_songs;
2018-02-27 18:06:05 +01:00
if (item->Metadata().has_cue()) {
cue_selected = true;
}
else if (item->Metadata().IsEditable()) {
++editable;
2018-02-27 18:06:05 +01:00
}
if (src_idx.data(Playlist::Role_QueuePosition).toInt() == -1) ++not_in_queue;
else ++in_queue;
2018-02-27 18:06:05 +01:00
if (item->GetShouldSkip()) ++in_skipped;
else ++not_in_skipped;
2020-02-22 15:31:25 +01:00
2018-02-27 18:06:05 +01:00
}
// this is available when we have one or many files and at least one of those is not CUE related
ui_->action_edit_track->setEnabled(local_songs > 0 && editable > 0);
ui_->action_edit_track->setVisible(local_songs > 0 && editable > 0);
#ifdef HAVE_MUSICBRAINZ
ui_->action_auto_complete_tags->setEnabled(local_songs > 0 && editable > 0);
ui_->action_auto_complete_tags->setVisible(local_songs > 0 && editable > 0);
2018-07-16 07:23:37 +02:00
#endif
2019-06-30 21:06:07 +02:00
playlist_rescan_songs_->setEnabled(local_songs > 0 && editable > 0);
playlist_rescan_songs_->setVisible(local_songs > 0 && editable > 0);
2019-06-30 21:06:07 +02:00
#ifdef HAVE_GSTREAMER
2021-06-22 13:54:58 +02:00
ui_->action_add_files_to_transcoder->setEnabled(local_songs > 0 && editable > 0);
ui_->action_add_files_to_transcoder->setVisible(local_songs > 0 && editable > 0);
#endif
playlist_open_in_browser_->setVisible(selected > 0 && local_songs == selected);
2018-02-27 18:06:05 +01:00
bool track_column = (index.column() == Playlist::Column_Track);
ui_->action_renumber_tracks->setVisible(local_songs > 0 && !cue_selected && editable >= 2 && track_column);
ui_->action_selection_set_value->setVisible(editable >= 2 && !cue_selected && !track_column);
ui_->action_edit_value->setVisible(editable > 0 && !cue_selected);
ui_->action_remove_from_playlist->setEnabled(selected > 0);
ui_->action_remove_from_playlist->setVisible(selected > 0);
2018-02-27 18:06:05 +01:00
playlist_show_in_collection_->setVisible(false);
playlist_copy_to_collection_->setVisible(false);
playlist_move_to_collection_->setVisible(false);
2019-01-06 16:48:23 +01:00
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
2018-02-27 18:06:05 +01:00
playlist_copy_to_device_->setVisible(false);
2018-09-20 17:36:23 +02:00
#endif
playlist_organize_->setVisible(false);
playlist_delete_->setVisible(false);
2018-02-27 18:06:05 +01:00
playlist_copy_url_->setVisible(selected > 0);
2018-02-27 18:06:05 +01:00
if (selected < 1) {
playlist_queue_->setVisible(false);
playlist_queue_play_next_->setVisible(false);
2018-02-27 18:06:05 +01:00
playlist_skip_->setVisible(false);
}
else {
playlist_queue_->setVisible(true);
playlist_queue_play_next_->setVisible(true);
2018-02-27 18:06:05 +01:00
playlist_skip_->setVisible(true);
if (in_queue == 1 && not_in_queue == 0) playlist_queue_->setText(tr("Dequeue track"));
else if (in_queue > 1 && not_in_queue == 0) playlist_queue_->setText(tr("Dequeue selected tracks"));
else if (in_queue == 0 && not_in_queue == 1) playlist_queue_->setText(tr("Queue track"));
else if (in_queue == 0 && not_in_queue > 1) playlist_queue_->setText(tr("Queue selected tracks"));
else playlist_queue_->setText(tr("Toggle queue status"));
2021-08-23 21:21:08 +02:00
if (selected > 1) {
playlist_queue_play_next_->setText(tr("Queue selected tracks to play next"));
2021-08-23 21:21:08 +02:00
}
else {
playlist_queue_play_next_->setText(tr("Queue to play next"));
2021-08-23 21:21:08 +02:00
}
2018-02-27 18:06:05 +01:00
if (in_skipped == 1 && not_in_skipped == 0) playlist_skip_->setText(tr("Unskip track"));
else if (in_skipped > 1 && not_in_skipped == 0) playlist_skip_->setText(tr("Unskip selected tracks"));
else if (in_skipped == 0 && not_in_skipped == 1) playlist_skip_->setText(tr("Skip track"));
else if (in_skipped == 0 && not_in_skipped > 1) playlist_skip_->setText(tr("Skip selected tracks"));
else playlist_skip_->setText(tr("Toggle skip status"));
}
if (not_in_queue == 0) playlist_queue_->setIcon(IconLoader::Load("go-previous"));
else playlist_queue_->setIcon(IconLoader::Load("go-next"));
2019-08-29 22:11:22 +02:00
if (in_skipped < selected) playlist_skip_->setIcon(IconLoader::Load("media-skip-forward"));
else playlist_skip_->setIcon(IconLoader::Load("media-playback-start"));
2018-02-27 18:06:05 +01:00
if (!index.isValid()) {
ui_->action_selection_set_value->setVisible(false);
ui_->action_edit_value->setVisible(false);
}
else {
2018-10-02 00:38:52 +02:00
2020-06-15 17:59:02 +02:00
Playlist::Column column = static_cast<Playlist::Column>(index.column());
bool column_is_editable = (Playlist::column_is_editable(column) && editable > 0 && !cue_selected);
2018-02-27 18:06:05 +01:00
ui_->action_selection_set_value->setVisible(ui_->action_selection_set_value->isVisible() && column_is_editable);
ui_->action_edit_value->setVisible(ui_->action_edit_value->isVisible() && column_is_editable);
QString column_name = Playlist::column_name(column);
QString column_value = app_->playlist_manager()->current()->data(source_index).toString();
2018-02-27 18:06:05 +01:00
if (column_value.length() > 25) column_value = column_value.left(25) + "...";
2021-03-21 04:47:11 +01:00
ui_->action_selection_set_value->setText(tr("Set %1 to \"%2\"...").arg(column_name.toLower(), column_value));
2018-02-27 18:06:05 +01:00
ui_->action_edit_value->setText(tr("Edit tag \"%1\"...").arg(column_name));
// Is it a collection item?
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
2020-02-22 15:31:25 +01:00
if (item && item->IsLocalCollectionItem() && item->Metadata().id() != -1) {
playlist_organize_->setVisible(local_songs > 0 && editable > 0 && !cue_selected);
playlist_show_in_collection_->setVisible(true);
2018-02-27 18:06:05 +01:00
playlist_open_in_browser_->setVisible(true);
}
else {
playlist_copy_to_collection_->setVisible(local_songs > 0);
playlist_move_to_collection_->setVisible(local_songs > 0);
2018-02-27 18:06:05 +01:00
}
2018-09-20 17:36:23 +02:00
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
playlist_copy_to_device_->setVisible(local_songs > 0);
2018-02-27 18:06:05 +01:00
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
playlist_delete_->setVisible(delete_files_ && local_songs > 0);
#endif
2018-02-27 18:06:05 +01:00
// Remove old item actions, if any.
for (QAction *action : playlistitem_actions_) {
playlist_menu_->removeAction(action);
}
// Get the new item actions, and add them
playlistitem_actions_ = item->actions();
playlistitem_actions_separator_->setVisible(!playlistitem_actions_.isEmpty());
2021-07-11 09:49:38 +02:00
playlist_menu_->insertActions(playlistitem_actions_separator_, playlistitem_actions_);
2018-02-27 18:06:05 +01:00
}
//if it isn't the first time we right click, we need to remove the menu previously created
if (playlist_add_to_another_ != nullptr) {
playlist_menu_->removeAction(playlist_add_to_another_);
delete playlist_add_to_another_;
playlist_add_to_another_ = nullptr;
2018-02-27 18:06:05 +01:00
}
// Create the playlist submenu if songs are selected.
if (selected > 0) {
QMenu *add_to_another_menu = new QMenu(tr("Add to another playlist"), this);
add_to_another_menu->setIcon(IconLoader::Load("list-add"));
for (const PlaylistBackend::Playlist &playlist : app_->playlist_backend()->GetAllOpenPlaylists()) {
// don't add the current playlist
if (playlist.id != app_->playlist_manager()->current()->id()) {
QAction *existing_playlist = new QAction(this);
existing_playlist->setText(playlist.name);
existing_playlist->setData(playlist.id);
add_to_another_menu->addAction(existing_playlist);
}
2018-02-27 18:06:05 +01:00
}
add_to_another_menu->addSeparator();
// add to a new playlist
QAction *new_playlist = new QAction(this);
new_playlist->setText(tr("New playlist"));
new_playlist->setData(-1); // fake id
add_to_another_menu->addAction(new_playlist);
playlist_add_to_another_ = playlist_menu_->insertMenu(ui_->action_remove_from_playlist, add_to_another_menu);
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
QObject::connect(add_to_another_menu, &QMenu::triggered, this, &MainWindow::AddToPlaylistFromAction);
}
2018-02-27 18:06:05 +01:00
playlist_menu_->popup(global_pos);
2020-02-22 00:09:45 +01:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistPlay() {
if (app_->playlist_manager()->current()->current_row() == playlist_menu_index_.row()) {
2023-02-18 14:09:27 +01:00
app_->player()->PlayPause(0, Playlist::AutoScroll::Never);
2018-02-27 18:06:05 +01:00
}
else {
2023-02-18 14:09:27 +01:00
PlayIndex(playlist_menu_index_, Playlist::AutoScroll::Never);
2018-02-27 18:06:05 +01:00
}
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistStopAfter() {
app_->playlist_manager()->current()->StopAfter(playlist_menu_index_.row());
}
2019-06-30 21:06:07 +02:00
void MainWindow::RescanSongs() {
SongList songs;
2020-02-22 15:31:25 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
if (!item) continue;
if (item->IsLocalCollectionItem()) {
songs << item->Metadata();
}
2023-02-18 14:09:27 +01:00
else if (item->Metadata().source() == Song::Source::LocalFile) {
QPersistentModelIndex persistent_index = QPersistentModelIndex(source_index);
app_->playlist_manager()->current()->ItemReload(persistent_index, item->OriginalMetadata(), false);
}
2019-06-30 21:06:07 +02:00
}
if (!songs.isEmpty()) {
app_->collection()->Rescan(songs);
}
2019-06-30 21:06:07 +02:00
}
2018-02-27 18:06:05 +01:00
void MainWindow::EditTracks() {
2018-10-20 22:16:22 +02:00
2018-02-27 18:06:05 +01:00
SongList songs;
2023-02-18 14:09:27 +01:00
PlaylistItemPtrList items;
2018-02-27 18:06:05 +01:00
2020-02-22 15:31:25 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
2020-02-22 00:09:45 +01:00
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
if (!item) continue;
Song song = item->OriginalMetadata();
2018-02-27 18:06:05 +01:00
if (song.IsEditable()) {
songs << song;
items << item;
}
}
if (items.isEmpty()) return;
2018-02-27 18:06:05 +01:00
edit_tag_dialog_->SetSongs(songs, items);
edit_tag_dialog_->show();
edit_tag_dialog_->raise();
2018-10-20 22:16:22 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::EditTagDialogAccepted() {
2018-10-19 20:18:46 +02:00
for (PlaylistItemPtr item : edit_tag_dialog_->playlist_items()) {
2018-02-27 18:06:05 +01:00
item->Reload();
}
2020-02-22 00:09:45 +01:00
// FIXME: This is really lame but we don't know what rows have changed.
2018-02-27 18:06:05 +01:00
ui_->playlist->view()->update();
app_->playlist_manager()->current()->ScheduleSaveAsync();
2018-10-19 20:18:46 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::RenumberTracks() {
2018-10-19 20:18:46 +02:00
2020-02-22 15:31:25 +01:00
QModelIndexList indexes = ui_->playlist->view()->selectionModel()->selectedRows();
2018-02-27 18:06:05 +01:00
int track = 1;
// Get the index list in order
2018-10-19 20:18:46 +02:00
std::stable_sort(indexes.begin(), indexes.end());
2018-02-27 18:06:05 +01:00
// if first selected song has a track number set, start from that offset
if (!indexes.isEmpty()) {
const Song first_song = app_->playlist_manager()->current()->item_at(indexes[0].row())->OriginalMetadata();
2018-02-27 18:06:05 +01:00
if (first_song.track() > 0) track = first_song.track();
}
2020-02-22 00:09:45 +01:00
for (const QModelIndex &proxy_index : indexes) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
Song song = item->OriginalMetadata();
2018-02-27 18:06:05 +01:00
if (song.IsEditable()) {
song.set_track(track);
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
2021-01-29 18:47:50 +01:00
QPersistentModelIndex persistent_index = QPersistentModelIndex(source_index);
QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection);
2018-02-27 18:06:05 +01:00
}
2020-02-22 00:09:45 +01:00
++track;
2018-02-27 18:06:05 +01:00
}
2018-10-19 20:18:46 +02:00
2018-02-27 18:06:05 +01:00
}
2020-08-23 19:17:50 +02:00
void MainWindow::SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx) {
2020-08-23 19:17:50 +02:00
if (reply->is_successful() && idx.isValid()) {
2021-07-11 09:49:38 +02:00
app_->playlist_manager()->current()->ReloadItems(QList<int>() << idx.row());
2018-02-27 18:06:05 +01:00
}
reply->deleteLater();
2018-02-27 18:06:05 +01:00
}
void MainWindow::SelectionSetValue() {
2018-10-20 22:16:22 +02:00
2020-06-15 17:59:02 +02:00
Playlist::Column column = static_cast<Playlist::Column>(playlist_menu_index_.column());
QVariant column_value = app_->playlist_manager()->current()->data(playlist_menu_index_);
2018-02-27 18:06:05 +01:00
2020-02-22 15:31:25 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
Song song = item->OriginalMetadata();
if (!song.is_valid()) continue;
if (song.url().isLocalFile() && Playlist::set_column_value(song, column, column_value)) {
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
2021-01-29 18:47:50 +01:00
QPersistentModelIndex persistent_index = QPersistentModelIndex(source_index);
QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection);
2018-02-27 18:06:05 +01:00
}
2023-02-18 14:09:27 +01:00
else if (song.source() == Song::Source::Stream) {
app_->playlist_manager()->current()->setData(source_index, column_value, 0);
}
2018-02-27 18:06:05 +01:00
}
2018-10-20 22:16:22 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::EditValue() {
2018-10-20 22:16:22 +02:00
2018-02-27 18:06:05 +01:00
QModelIndex current = ui_->playlist->view()->currentIndex();
if (!current.isValid()) return;
// Edit the last column that was right-clicked on. If nothing's ever been right clicked then look for the first editable column.
2018-02-27 18:06:05 +01:00
int column = playlist_menu_index_.column();
if (column == -1) {
for (int i = 0; i < ui_->playlist->view()->model()->columnCount(); ++i) {
if (ui_->playlist->view()->isColumnHidden(i)) continue;
2022-06-13 00:23:42 +02:00
if (!Playlist::column_is_editable(static_cast<Playlist::Column>(i))) continue;
2018-02-27 18:06:05 +01:00
column = i;
break;
}
}
ui_->playlist->view()->edit(current.sibling(current.row(), column));
2018-02-27 18:06:05 +01:00
}
void MainWindow::AddFile() {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
// Last used directory
QString directory = settings_.value("add_media_path", QDir::currentPath()).toString();
2018-02-27 18:06:05 +01:00
PlaylistParser parser(app_->collection_backend());
// Show dialog
2023-02-18 14:09:27 +01:00
QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter, parser.filters(PlaylistParser::Type::Load), tr(kAllFilesFilterSpec)));
2018-02-27 18:06:05 +01:00
if (file_names.isEmpty()) return;
// Save last used directory
settings_.setValue("add_media_path", file_names[0]);
// Convert to URLs
QList<QUrl> urls;
2021-06-20 19:04:08 +02:00
urls.reserve(file_names.count());
for (const QString &path : file_names) {
2018-02-27 18:06:05 +01:00
urls << QUrl::fromLocalFile(QFileInfo(path).canonicalFilePath());
}
2020-04-23 21:08:28 +02:00
MimeData *mimedata = new MimeData;
mimedata->setUrls(urls);
AddToPlaylist(mimedata);
2018-10-20 22:16:22 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::AddFolder() {
2018-10-20 22:16:22 +02:00
2018-02-27 18:06:05 +01:00
// Last used directory
QString directory = settings_.value("add_folder_path", QDir::currentPath()).toString();
2018-02-27 18:06:05 +01:00
// Show dialog
2020-02-22 00:09:45 +01:00
directory = QFileDialog::getExistingDirectory(this, tr("Add folder"), directory);
2018-02-27 18:06:05 +01:00
if (directory.isEmpty()) return;
// Save last used directory
settings_.setValue("add_folder_path", directory);
// Add media
2020-04-23 21:08:28 +02:00
MimeData *mimedata = new MimeData;
mimedata->setUrls(QList<QUrl>() << QUrl::fromLocalFile(QFileInfo(directory).canonicalFilePath()));
AddToPlaylist(mimedata);
2018-10-20 22:16:22 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::AddCDTracks() {
2020-04-23 21:08:28 +02:00
MimeData *mimedata = new MimeData;
// We are putting empty data, but we specify cdda mimetype to indicate that we want to load audio cd tracks
2020-04-23 21:08:28 +02:00
mimedata->open_in_new_playlist_ = true;
mimedata->setData(Playlist::kCddaMimeType, QByteArray());
AddToPlaylist(mimedata);
2018-02-27 18:06:05 +01:00
}
void MainWindow::AddStream() {
add_stream_dialog_->show();
add_stream_dialog_->raise();
}
void MainWindow::AddStreamAccepted() {
2020-04-23 21:08:28 +02:00
MimeData *mimedata = new MimeData;
mimedata->setUrls(QList<QUrl>() << add_stream_dialog_->url());
AddToPlaylist(mimedata);
}
2018-02-27 18:06:05 +01:00
void MainWindow::ShowInCollection() {
// Show the first valid selected track artist/album in CollectionView
2020-02-22 00:09:45 +01:00
SongList songs;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (item && item->IsLocalCollectionItem()) {
songs << item->OriginalMetadata();
2018-02-27 18:06:05 +01:00
break;
}
}
QString search;
if (!songs.isEmpty()) {
search = "artist:" + songs.first().artist() + " album:" + songs.first().album();
2018-02-27 18:06:05 +01:00
}
2021-06-28 00:07:58 +02:00
collection_view_->filter_widget()->ShowInCollection(search);
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistRemoveCurrent() {
ui_->playlist->view()->RemoveSelected();
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistClearCurrent() {
if (app_->playlist_manager()->current()->rowCount() > Playlist::kUndoItemLimit) {
2022-03-22 21:09:05 +01:00
QMessageBox messagebox(QMessageBox::Warning, tr("Clear playlist"), tr("Playlist has %1 songs, too large to undo, are you sure you want to clear the playlist?").arg(app_->playlist_manager()->current()->rowCount()), QMessageBox::Ok | QMessageBox::Cancel);
messagebox.setTextFormat(Qt::RichText);
int result = messagebox.exec();
switch (result) {
2021-07-11 09:49:38 +02:00
case QMessageBox::Ok:
break;
case QMessageBox::Cancel:
default:
return;
}
}
app_->playlist_manager()->ClearCurrent();
}
void MainWindow::PlaylistEditFinished(const int playlist_id, const QModelIndex &idx) {
if (app_->playlist_manager()->current() && playlist_id == app_->playlist_manager()->current()->id() && idx == playlist_menu_index_) {
SelectionSetValue();
}
2018-02-27 18:06:05 +01:00
}
void MainWindow::CommandlineOptionsReceived(const QByteArray &string_options) {
2018-02-27 18:06:05 +01:00
CommandlineOptions options;
options.Load(string_options);
2018-02-27 18:06:05 +01:00
if (options.is_empty()) {
raise();
2018-02-27 18:06:05 +01:00
show();
activateWindow();
2020-10-05 19:08:09 +02:00
hidden_ = false;
return;
2018-02-27 18:06:05 +01:00
}
CommandlineOptionsReceived(options);
2020-10-05 19:08:09 +02:00
2018-02-27 18:06:05 +01:00
}
2023-07-02 23:33:12 +02:00
void MainWindow::CommandlineOptionsReceived(const quint32 instanceId, const QByteArray &string_options) {
Q_UNUSED(instanceId);
CommandlineOptionsReceived(string_options);
}
void MainWindow::CommandlineOptionsReceived(const CommandlineOptions &options) {
2018-02-27 18:06:05 +01:00
switch (options.player_action()) {
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::Play:
2018-02-27 18:06:05 +01:00
if (options.urls().empty()) {
app_->player()->Play();
}
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::PlayPause:
app_->player()->PlayPause(0, Playlist::AutoScroll::Maybe);
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::Pause:
2018-02-27 18:06:05 +01:00
app_->player()->Pause();
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::Stop:
2018-02-27 18:06:05 +01:00
app_->player()->Stop();
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::StopAfterCurrent:
2018-02-27 18:06:05 +01:00
app_->player()->StopAfterCurrent();
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::Previous:
2018-02-27 18:06:05 +01:00
app_->player()->Previous();
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::Next:
2018-02-27 18:06:05 +01:00
app_->player()->Next();
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::PlayPlaylist:
if (options.playlist_name().isEmpty()) {
qLog(Error) << "ERROR: playlist name missing";
}
else {
app_->player()->PlayPlaylist(options.playlist_name());
}
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::RestartOrPrevious:
2018-02-27 18:06:05 +01:00
app_->player()->RestartOrPrevious();
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::ResizeWindow:{
if (options.window_size().contains('x') && options.window_size().length() >= 4) {
QString str_w = options.window_size().left(options.window_size().indexOf('x'));
QString str_h = options.window_size().right(options.window_size().length() - options.window_size().indexOf('x') - 1);
bool w_ok = false;
bool h_ok = false;
int w = str_w.toInt(&w_ok);
int h = str_h.toInt(&h_ok);
if (w_ok && h_ok) {
QSize window_size(w, h);
if (window_size.isValid()) {
QScreen *screen = Utilities::GetScreen(this);
if (screen) {
const QRect sr = screen->availableGeometry();
window_size = window_size.boundedTo(sr.size());
if (window_size.width() >= sr.width() && window_size.height() >= sr.height()) {
resize(window_size);
showMaximized();
}
else {
showNormal();
resize(window_size);
const QRect wr({}, size().boundedTo(sr.size()));
resize(wr.size());
move(sr.center() - wr.center());
}
}
}
}
}
break;
}
2023-02-18 14:09:27 +01:00
case CommandlineOptions::PlayerAction::None:
2018-02-27 18:06:05 +01:00
break;
2018-02-27 18:06:05 +01:00
}
if (!options.urls().empty()) {
2020-04-13 19:04:06 +02:00
#ifdef HAVE_TIDAL
2020-04-25 00:07:42 +02:00
for (const QUrl &url : options.urls()) {
2020-04-13 19:04:06 +02:00
if (url.scheme() == "tidal" && url.host() == "login") {
2020-05-13 21:56:11 +02:00
emit AuthorizationUrlReceived(url);
2020-04-13 19:04:06 +02:00
return;
}
}
#endif
2020-04-23 21:08:28 +02:00
MimeData *mimedata = new MimeData;
mimedata->setUrls(options.urls());
2018-02-27 18:06:05 +01:00
// Behaviour depends on command line options, so set it here
2020-04-23 21:08:28 +02:00
mimedata->override_user_settings_ = true;
2018-02-27 18:06:05 +01:00
2023-02-18 14:09:27 +01:00
if (options.player_action() == CommandlineOptions::PlayerAction::Play) mimedata->play_now_ = true;
2020-04-23 21:08:28 +02:00
else ApplyPlayBehaviour(doubleclick_playmode_, mimedata);
2018-02-27 18:06:05 +01:00
switch (options.url_list_action()) {
2023-02-18 14:09:27 +01:00
case CommandlineOptions::UrlListAction::Load:
2020-04-23 21:08:28 +02:00
mimedata->clear_first_ = true;
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::UrlListAction::Append:
2018-02-27 18:06:05 +01:00
// Nothing to do
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::UrlListAction::None:
2020-04-23 21:08:28 +02:00
ApplyAddBehaviour(doubleclick_addmode_, mimedata);
2018-02-27 18:06:05 +01:00
break;
2023-02-18 14:09:27 +01:00
case CommandlineOptions::UrlListAction::CreateNew:
2020-04-23 21:08:28 +02:00
mimedata->name_for_new_playlist_ = options.playlist_name();
2023-02-18 14:09:27 +01:00
ApplyAddBehaviour(BehaviourSettingsPage::AddBehaviour::OpenInNew, mimedata);
2018-02-27 18:06:05 +01:00
break;
}
2020-04-23 21:08:28 +02:00
AddToPlaylist(mimedata);
2018-02-27 18:06:05 +01:00
}
if (options.set_volume() != -1) app_->player()->SetVolume(static_cast<uint>(qBound(0, options.set_volume(), 100)));
2018-02-27 18:06:05 +01:00
if (options.volume_modifier() != 0) {
app_->player()->SetVolume(static_cast<uint>(qBound(0, static_cast<int>(app_->player()->GetVolume()) + options.volume_modifier(), 100)));
2018-02-27 18:06:05 +01:00
}
if (options.seek_to() != -1) {
app_->player()->SeekTo(options.seek_to());
}
else if (options.seek_by() != 0) {
2020-02-22 00:09:45 +01:00
app_->player()->SeekTo(app_->player()->engine()->position_nanosec() / kNsecPerSec + options.seek_by());
2018-02-27 18:06:05 +01:00
}
2023-04-22 19:13:42 +02:00
if (options.play_track_at() != -1) app_->player()->PlayAt(options.play_track_at(), 0, EngineBase::TrackChangeType::Manual, Playlist::AutoScroll::Maybe, true);
2018-02-27 18:06:05 +01:00
if (options.show_osd()) app_->player()->ShowOSD();
if (options.toggle_pretty_osd()) app_->player()->TogglePrettyOSD();
2018-02-27 18:06:05 +01:00
}
void MainWindow::ForceShowOSD(const Song &song, const bool toggle) {
2019-09-15 20:27:32 +02:00
Q_UNUSED(song);
2018-02-27 18:06:05 +01:00
if (toggle) {
osd_->SetPrettyOSDToggleMode(toggle);
}
osd_->ReshowCurrentSong();
2019-09-15 20:27:32 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::Activate() {
show();
}
bool MainWindow::LoadUrl(const QString &url) {
2018-02-27 18:06:05 +01:00
2021-04-11 18:33:35 +02:00
if (QFile::exists(url)) {
MimeData *mimedata = new MimeData;
mimedata->setUrls(QList<QUrl>() << QUrl::fromLocalFile(url));
AddToPlaylist(mimedata);
return true;
}
#ifdef HAVE_TIDAL
else if (url.startsWith("tidal://login")) {
emit AuthorizationUrlReceived(QUrl(url));
return true;
}
#endif
else {
qLog(Error) << "Can't open" << url;
}
2018-02-27 18:06:05 +01:00
2021-04-11 18:33:35 +02:00
return false;
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistUndoRedoChanged(QAction *undo, QAction *redo) {
2018-02-27 18:06:05 +01:00
playlist_menu_->insertAction(playlist_undoredo_, undo);
playlist_menu_->insertAction(playlist_undoredo_, redo);
}
void MainWindow::AddFilesToTranscoder() {
#ifdef HAVE_GSTREAMER
2018-02-27 18:06:05 +01:00
QStringList filenames;
2020-02-22 15:31:25 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
if (!item) continue;
Song song = item->OriginalMetadata();
2020-02-22 00:09:45 +01:00
if (!song.is_valid() || !song.url().isLocalFile()) continue;
2018-02-27 18:06:05 +01:00
filenames << song.url().toLocalFile();
}
if (filenames.isEmpty()) return;
2018-02-27 18:06:05 +01:00
transcode_dialog_->SetFilenames(filenames);
ShowTranscodeDialog();
2018-02-27 18:06:05 +01:00
#endif
}
2018-02-27 18:06:05 +01:00
void MainWindow::ShowCollectionConfig() {
2023-02-18 14:09:27 +01:00
settings_dialog_->OpenAtPage(SettingsDialog::Page::Collection);
2018-02-27 18:06:05 +01:00
}
2020-02-22 00:09:45 +01:00
void MainWindow::TaskCountChanged(const int count) {
2018-02-27 18:06:05 +01:00
if (count == 0) {
ui_->status_bar_stack->setCurrentWidget(ui_->playlist_summary_page);
}
else {
ui_->status_bar_stack->setCurrentWidget(ui_->multi_loading_indicator);
}
2018-02-27 18:06:05 +01:00
}
2020-02-22 00:09:45 +01:00
void MainWindow::PlayingWidgetPositionChanged(const bool above_status_bar) {
2018-02-27 18:06:05 +01:00
if (above_status_bar) ui_->status_bar->setParent(ui_->centralWidget);
else ui_->status_bar->setParent(ui_->player_controls_container);
2018-02-27 18:06:05 +01:00
ui_->status_bar->parentWidget()->layout()->addWidget(ui_->status_bar);
ui_->status_bar->show();
2018-02-27 18:06:05 +01:00
}
void MainWindow::CopyFilesToCollection(const QList<QUrl> &urls) {
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
organize_dialog_->SetUrls(urls);
organize_dialog_->SetCopy(true);
organize_dialog_->show();
organize_dialog_->raise();
2018-02-27 18:06:05 +01:00
}
void MainWindow::MoveFilesToCollection(const QList<QUrl> &urls) {
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
organize_dialog_->SetUrls(urls);
organize_dialog_->SetCopy(false);
organize_dialog_->show();
organize_dialog_->raise();
2018-02-27 18:06:05 +01:00
}
void MainWindow::CopyFilesToDevice(const QList<QUrl> &urls) {
2019-01-06 16:48:23 +01:00
#if defined(HAVE_GSTREAMER) && !defined(Q_OS_WIN)
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
organize_dialog_->SetCopy(true);
if (organize_dialog_->SetUrls(urls)) {
organize_dialog_->show();
organize_dialog_->raise();
}
2018-02-27 18:06:05 +01:00
else {
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
2018-02-27 18:06:05 +01:00
}
2019-09-19 17:44:14 +02:00
#else
Q_UNUSED(urls);
2018-09-20 17:36:23 +02:00
#endif
2018-02-27 18:06:05 +01:00
}
void MainWindow::EditFileTags(const QList<QUrl> &urls) {
2018-02-27 18:06:05 +01:00
SongList songs;
2021-06-20 19:04:08 +02:00
songs.reserve(urls.count());
for (const QUrl &url : urls) {
2018-02-27 18:06:05 +01:00
Song song;
song.set_url(url);
song.set_valid(true);
2023-02-18 14:09:27 +01:00
song.set_filetype(Song::FileType::MPEG);
2018-02-27 18:06:05 +01:00
songs << song;
}
edit_tag_dialog_->SetSongs(songs);
edit_tag_dialog_->show();
edit_tag_dialog_->raise();
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistCopyToCollection() {
PlaylistOrganizeSelected(true);
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistMoveToCollection() {
PlaylistOrganizeSelected(false);
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistOrganizeSelected(const bool copy) {
2018-02-27 18:06:05 +01:00
SongList songs;
2020-02-22 00:09:45 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
Song song = item->OriginalMetadata();
2020-02-22 00:09:45 +01:00
if (!song.is_valid() || !song.url().isLocalFile()) continue;
songs << song;
2018-02-27 18:06:05 +01:00
}
if (songs.isEmpty()) return;
2018-02-27 18:06:05 +01:00
organize_dialog_->SetDestinationModel(app_->collection_model()->directory_model());
organize_dialog_->SetSongs(songs);
organize_dialog_->SetCopy(copy);
organize_dialog_->show();
organize_dialog_->raise();
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistOpenInBrowser() {
QList<QUrl> urls;
2020-02-22 00:09:45 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
urls << QUrl(source_index.sibling(source_index.row(), Playlist::Column_Filename).data().toString());
2018-02-27 18:06:05 +01:00
}
Utilities::OpenInFileBrowser(urls);
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistCopyUrl() {
QList<QUrl> urls;
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
urls << item->StreamUrl();
}
if (urls.count() > 0) {
QMimeData mime_data;
mime_data.setUrls(urls);
QApplication::clipboard()->setText(mime_data.text());
}
}
2018-02-27 18:06:05 +01:00
void MainWindow::PlaylistQueue() {
2021-06-20 19:04:08 +02:00
const QModelIndexList selected_rows = ui_->playlist->view()->selectionModel()->selectedRows();
2018-02-27 18:06:05 +01:00
QModelIndexList indexes;
2021-06-20 19:04:08 +02:00
indexes.reserve(selected_rows.count());
for (const QModelIndex &proxy_index : selected_rows) {
2022-08-09 17:23:46 +02:00
indexes << app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2018-02-27 18:06:05 +01:00
}
app_->playlist_manager()->current()->queue()->ToggleTracks(indexes);
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistQueuePlayNext() {
2021-06-20 19:04:08 +02:00
QModelIndexList selected_rows = ui_->playlist->view()->selectionModel()->selectedRows();
QModelIndexList indexes;
2021-06-20 19:04:08 +02:00
indexes.reserve(selected_rows.count());
for (const QModelIndex &proxy_index : selected_rows) {
2022-08-09 17:23:46 +02:00
indexes << app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
}
app_->playlist_manager()->current()->queue()->InsertFirst(indexes);
}
2018-02-27 18:06:05 +01:00
void MainWindow::PlaylistSkip() {
2021-06-20 19:04:08 +02:00
const QModelIndexList selected_rows = ui_->playlist->view()->selectionModel()->selectedRows();
2018-02-27 18:06:05 +01:00
QModelIndexList indexes;
2021-06-20 19:04:08 +02:00
indexes.reserve(selected_rows.count());
for (const QModelIndex &proxy_index : selected_rows) {
2022-08-09 17:23:46 +02:00
indexes << app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2018-02-27 18:06:05 +01:00
}
app_->playlist_manager()->current()->SkipTracks(indexes);
}
void MainWindow::PlaylistCopyToDevice() {
2019-01-06 16:48:23 +01:00
#ifndef Q_OS_WIN
2020-02-22 00:09:45 +01:00
2018-02-27 18:06:05 +01:00
SongList songs;
2020-02-22 00:09:45 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_index.row());
if (!item) continue;
Song song = item->OriginalMetadata();
2020-02-22 00:09:45 +01:00
if (!song.is_valid() || !song.url().isLocalFile()) continue;
songs << song;
2018-02-27 18:06:05 +01:00
}
if (songs.isEmpty()) return;
2018-02-27 18:06:05 +01:00
organize_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
organize_dialog_->SetCopy(true);
if (organize_dialog_->SetSongs(songs)) {
organize_dialog_->show();
organize_dialog_->raise();
}
2018-02-27 18:06:05 +01:00
else {
2018-09-20 17:36:23 +02:00
QMessageBox::warning(this, tr("Error"), tr("None of the selected songs were suitable for copying to a device"));
2018-02-27 18:06:05 +01:00
}
2020-02-22 00:09:45 +01:00
2018-09-20 17:36:23 +02:00
#endif
2018-02-27 18:06:05 +01:00
}
void MainWindow::ChangeCollectionFilterMode(QAction *action) {
2018-02-27 18:06:05 +01:00
if (action == collection_show_duplicates_) {
2023-02-18 14:09:27 +01:00
collection_view_->filter_widget()->SetFilterMode(CollectionFilterOptions::FilterMode::Duplicates);
2018-02-27 18:06:05 +01:00
}
else if (action == collection_show_untagged_) {
2023-02-18 14:09:27 +01:00
collection_view_->filter_widget()->SetFilterMode(CollectionFilterOptions::FilterMode::Untagged);
2018-02-27 18:06:05 +01:00
}
else {
2023-02-18 14:09:27 +01:00
collection_view_->filter_widget()->SetFilterMode(CollectionFilterOptions::FilterMode::All);
2018-02-27 18:06:05 +01:00
}
2018-02-27 18:06:05 +01:00
}
void MainWindow::ShowCoverManager() {
cover_manager_->show();
cover_manager_->raise();
}
void MainWindow::ShowEqualizer() {
equalizer_->show();
equalizer_->raise();
2018-02-27 18:06:05 +01:00
}
SettingsDialog *MainWindow::CreateSettingsDialog() {
2018-02-27 18:06:05 +01:00
2020-08-09 01:37:00 +02:00
SettingsDialog *settings_dialog = new SettingsDialog(app_, osd_, this);
#ifdef HAVE_GLOBALSHORTCUTS
2021-01-26 19:13:29 +01:00
settings_dialog->SetGlobalShortcutManager(globalshortcuts_manager_);
#endif
2018-02-27 18:06:05 +01:00
// Settings
2021-01-26 16:48:04 +01:00
QObject::connect(settings_dialog, &SettingsDialog::ReloadSettings, this, &MainWindow::ReloadAllSettings);
2018-02-27 18:06:05 +01:00
// Allows custom notification preview
2021-01-26 16:48:04 +01:00
QObject::connect(settings_dialog, &SettingsDialog::NotificationPreview, this, &MainWindow::HandleNotificationPreview);
2018-02-27 18:06:05 +01:00
return settings_dialog;
}
void MainWindow::OpenSettingsDialog() {
settings_dialog_->show();
settings_dialog_->raise();
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::OpenSettingsDialogAtPage(SettingsDialog::Page page) {
settings_dialog_->OpenAtPage(page);
}
EditTagDialog *MainWindow::CreateEditTagDialog() {
2018-02-27 18:06:05 +01:00
EditTagDialog *edit_tag_dialog = new EditTagDialog(app_);
2021-01-26 16:48:04 +01:00
QObject::connect(edit_tag_dialog, &EditTagDialog::accepted, this, &MainWindow::EditTagDialogAccepted);
QObject::connect(edit_tag_dialog, &EditTagDialog::Error, this, &MainWindow::ShowErrorDialog);
2018-02-27 18:06:05 +01:00
return edit_tag_dialog;
}
void MainWindow::ShowAboutDialog() {
about_dialog_->show();
about_dialog_->raise();
2018-02-27 18:06:05 +01:00
}
void MainWindow::ShowTranscodeDialog() {
#ifdef HAVE_GSTREAMER
2018-02-27 18:06:05 +01:00
transcode_dialog_->show();
transcode_dialog_->raise();
#endif
2018-02-27 18:06:05 +01:00
}
void MainWindow::ShowErrorDialog(const QString &message) {
2018-02-27 18:06:05 +01:00
error_dialog_->ShowMessage(message);
}
void MainWindow::CheckFullRescanRevisions() {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
int from = app_->database()->startup_schema_version();
int to = app_->database()->current_schema_version();
// if we're restoring DB from scratch or nothing has changed, do nothing
2018-02-27 18:06:05 +01:00
if (from == 0 || from == to) {
return;
}
// Collect all reasons
2018-02-27 18:06:05 +01:00
QSet<QString> reasons;
2021-08-23 21:21:08 +02:00
for (int i = from; i <= to; ++i) {
2018-02-27 18:06:05 +01:00
QString reason = app_->collection()->full_rescan_reason(i);
if (!reason.isEmpty()) {
reasons.insert(reason);
}
}
// if we have any...
if (!reasons.isEmpty()) {
QString message = tr("The version of Strawberry you've just updated to requires a full collection rescan because of the new features listed below:") + "<ul>";
2021-07-11 09:49:38 +02:00
for (const QString &reason : reasons) {
2018-02-27 18:06:05 +01:00
message += ("<li>" + reason + "</li>");
}
message += "</ul>" + tr("Would you like to run a full rescan right now?");
2018-10-20 22:16:22 +02:00
if (QMessageBox::question(this, tr("Collection rescan notice"), message, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
2018-02-27 18:06:05 +01:00
app_->collection()->FullScan();
}
}
}
void MainWindow::PlaylistViewSelectionModelChanged() {
2018-10-02 00:38:52 +02:00
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->playlist->view()->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::PlaylistCurrentChanged);
2018-02-27 18:06:05 +01:00
}
void MainWindow::PlaylistCurrentChanged(const QModelIndex &proxy_current) {
2019-09-15 20:27:32 +02:00
2022-08-09 17:23:46 +02:00
const QModelIndex source_current = app_->playlist_manager()->current()->filter()->mapToSource(proxy_current);
2018-02-27 18:06:05 +01:00
// If the user moves the current index using the keyboard and then presses
// F2, we don't want that editing the last column that was right clicked on.
if (source_current != playlist_menu_index_) playlist_menu_index_ = QModelIndex();
2019-09-15 20:27:32 +02:00
2018-02-27 18:06:05 +01:00
}
void MainWindow::Raise() {
2020-10-05 19:08:09 +02:00
2018-02-27 18:06:05 +01:00
show();
activateWindow();
2020-10-05 19:08:09 +02:00
hidden_ = false;
2018-02-27 18:06:05 +01:00
}
#ifdef Q_OS_WIN
2022-03-22 21:09:05 +01:00
# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) {
2022-03-22 21:09:05 +01:00
# else
2019-08-29 21:32:52 +02:00
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) {
2022-03-22 21:09:05 +01:00
# endif
2019-08-29 21:32:52 +02:00
if (exit_count_ == 0 && message) {
MSG *msg = static_cast<MSG*>(message);
thumbbar_->HandleWinEvent(msg);
}
return QMainWindow::nativeEvent(eventType, message, result);
2018-02-27 18:06:05 +01:00
}
#endif // Q_OS_WIN
2018-02-27 18:06:05 +01:00
void MainWindow::AutoCompleteTags() {
#ifdef HAVE_MUSICBRAINZ
2020-02-22 00:09:45 +01:00
autocomplete_tag_items_.clear();
2018-02-27 18:06:05 +01:00
// Create the tag fetching stuff if it hasn't been already
if (!tag_fetcher_) {
tag_fetcher_ = make_unique<TagFetcher>(app_->network());
track_selection_dialog_ = make_unique<TrackSelectionDialog>();
2018-02-27 18:06:05 +01:00
track_selection_dialog_->set_save_on_close(true);
QObject::connect(&*tag_fetcher_, &TagFetcher::ResultAvailable, &*track_selection_dialog_, &TrackSelectionDialog::FetchTagFinished, Qt::QueuedConnection);
QObject::connect(&*tag_fetcher_, &TagFetcher::Progress, &*track_selection_dialog_, &TrackSelectionDialog::FetchTagProgress);
QObject::connect(&*track_selection_dialog_, &TrackSelectionDialog::accepted, this, &MainWindow::AutoCompleteTagsAccepted);
QObject::connect(&*track_selection_dialog_, &TrackSelectionDialog::finished, &*tag_fetcher_, &TagFetcher::Cancel);
QObject::connect(&*track_selection_dialog_, &TrackSelectionDialog::Error, this, &MainWindow::ShowErrorDialog);
2018-02-27 18:06:05 +01:00
}
// Get the selected songs and start fetching tags for them
SongList songs;
2020-02-22 15:31:25 +01:00
for (const QModelIndex &proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
const QModelIndex source_index = app_->playlist_manager()->current()->filter()->mapToSource(proxy_index);
2020-02-22 00:09:45 +01:00
if (!source_index.isValid()) continue;
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(source_index.row()));
if (!item) continue;
Song song = item->OriginalMetadata();
2018-02-27 18:06:05 +01:00
if (song.IsEditable()) {
songs << song;
autocomplete_tag_items_ << item;
}
}
if (songs.isEmpty()) return;
2018-02-27 18:06:05 +01:00
track_selection_dialog_->Init(songs);
tag_fetcher_->StartFetch(songs);
track_selection_dialog_->show();
track_selection_dialog_->raise();
#endif
2018-02-27 18:06:05 +01:00
}
void MainWindow::AutoCompleteTagsAccepted() {
2018-10-02 00:38:52 +02:00
for (PlaylistItemPtr item : autocomplete_tag_items_) {
2018-02-27 18:06:05 +01:00
item->Reload();
}
autocomplete_tag_items_.clear();
2018-02-27 18:06:05 +01:00
// This is really lame but we don't know what rows have changed
ui_->playlist->view()->update();
2018-02-27 18:06:05 +01:00
}
2021-06-20 19:04:08 +02:00
void MainWindow::HandleNotificationPreview(const OSDBase::Behaviour type, const QString &line1, const QString &line2) {
2018-02-27 18:06:05 +01:00
if (!app_->playlist_manager()->current()->GetAllSongs().isEmpty()) {
// Show a preview notification for the first song in the current playlist
osd_->ShowPreview(type, line1, line2, app_->playlist_manager()->current()->GetAllSongs().first());
}
else {
qLog(Debug) << "The current playlist is empty, showing a fake song";
// Create a fake song
2023-02-18 14:09:27 +01:00
Song fake(Song::Source::LocalFile);
2018-02-27 18:06:05 +01:00
fake.Init("Title", "Artist", "Album", 123);
fake.set_genre("Classical");
fake.set_composer("Anonymous");
fake.set_performer("Anonymous");
fake.set_track(1);
fake.set_disc(1);
fake.set_year(2011);
osd_->ShowPreview(type, line1, line2, fake);
}
}
void MainWindow::ShowConsole() {
console_->show();
console_->raise();
2018-02-27 18:06:05 +01:00
}
void MainWindow::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Space) {
2023-02-18 14:09:27 +01:00
app_->player()->PlayPause(0, Playlist::AutoScroll::Never);
e->accept();
2018-02-27 18:06:05 +01:00
}
else if (e->key() == Qt::Key_Left) {
2018-02-27 18:06:05 +01:00
ui_->track_slider->Seek(-1);
e->accept();
2018-02-27 18:06:05 +01:00
}
else if (e->key() == Qt::Key_Right) {
2018-02-27 18:06:05 +01:00
ui_->track_slider->Seek(1);
e->accept();
2018-02-27 18:06:05 +01:00
}
else {
QMainWindow::keyPressEvent(e);
2018-02-27 18:06:05 +01:00
}
2018-02-27 18:06:05 +01:00
}
void MainWindow::LoadCoverFromFile() {
album_cover_choice_controller_->LoadCoverFromFile(&song_);
}
void MainWindow::LoadCoverFromURL() {
album_cover_choice_controller_->LoadCoverFromURL(&song_);
}
void MainWindow::SearchForCover() {
album_cover_choice_controller_->SearchForCover(&song_);
}
void MainWindow::SaveCoverToFile() {
album_cover_choice_controller_->SaveCoverToFileManual(song_, album_cover_);
}
void MainWindow::UnsetCover() {
album_cover_choice_controller_->UnsetCover(&song_);
}
void MainWindow::ClearCover() {
album_cover_choice_controller_->ClearCover(&song_);
}
void MainWindow::DeleteCover() {
album_cover_choice_controller_->DeleteCover(&song_, true);
}
void MainWindow::ShowCover() {
album_cover_choice_controller_->ShowCover(song_, album_cover_.image);
}
void MainWindow::SearchCoverAutomatically() {
GetCoverAutomatically();
}
void MainWindow::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result) {
if (song != song_playing_) return;
song_ = song;
album_cover_ = result.album_cover;
emit AlbumCoverReady(song, result.album_cover.image);
const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty();
2023-05-14 11:34:55 +02:00
album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset);
album_cover_choice_controller_->cover_to_file_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset);
album_cover_choice_controller_->cover_from_file_action()->setEnabled(enable_change_art);
album_cover_choice_controller_->cover_from_url_action()->setEnabled(enable_change_art);
album_cover_choice_controller_->search_for_cover_action()->setEnabled(app_->cover_providers()->HasAnyProviders() && enable_change_art);
2023-05-14 11:34:55 +02:00
album_cover_choice_controller_->unset_cover_action()->setEnabled(enable_change_art && !song.art_unset());
album_cover_choice_controller_->clear_cover_action()->setEnabled(enable_change_art && !song.art_manual().isEmpty());
2023-05-14 11:34:55 +02:00
album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && result.success && result.type != AlbumCoverLoaderResult::Type::Unset);
GetCoverAutomatically();
}
void MainWindow::GetCoverAutomatically() {
2018-10-02 00:38:52 +02:00
// Search for cover automatically?
const bool search = album_cover_choice_controller_->search_cover_auto_action()->isChecked() &&
2023-05-14 11:34:55 +02:00
!song_.art_unset() &&
!song_.art_embedded() &&
!song_.art_automatic_is_valid() &&
!song_.art_manual_is_valid() &&
!song_.effective_albumartist().isEmpty() &&
!song_.effective_album().isEmpty();
if (search) {
emit SearchCoverInProgress();
album_cover_choice_controller_->SearchCoverAutomatically(song_);
}
}
2020-02-22 00:09:45 +01:00
void MainWindow::ScrobblingEnabledChanged(const bool value) {
if (app_->scrobbler()->scrobble_button()) SetToggleScrobblingIcon(value);
}
2020-02-22 00:09:45 +01:00
void MainWindow::ScrobbleButtonVisibilityChanged(const bool value) {
2019-06-12 00:38:52 +02:00
ui_->button_scrobble->setVisible(value);
ui_->action_toggle_scrobbling->setVisible(value);
if (value) SetToggleScrobblingIcon(app_->scrobbler()->enabled());
}
2020-02-22 00:09:45 +01:00
void MainWindow::LoveButtonVisibilityChanged(const bool value) {
2019-06-12 00:38:52 +02:00
if (value)
ui_->widget_love->show();
else
ui_->widget_love->hide();
2021-05-20 21:40:08 +02:00
tray_icon_->LoveVisibilityChanged(value);
2019-06-12 00:38:52 +02:00
}
2020-02-22 00:09:45 +01:00
void MainWindow::SetToggleScrobblingIcon(const bool value) {
if (value) {
2020-04-25 00:07:42 +02:00
if (app_->playlist_manager()->active() && app_->playlist_manager()->active()->scrobbled())
ui_->action_toggle_scrobbling->setIcon(IconLoader::Load("scrobble", true, 22));
else
ui_->action_toggle_scrobbling->setIcon(IconLoader::Load("scrobble", true, 22)); // TODO: Create a faint version of the icon
}
else {
ui_->action_toggle_scrobbling->setIcon(IconLoader::Load("scrobble-disabled", true, 22));
}
}
2019-06-12 00:38:52 +02:00
void MainWindow::Love() {
app_->scrobbler()->Love();
ui_->button_love->setEnabled(false);
ui_->action_love->setEnabled(false);
2021-05-20 21:40:08 +02:00
tray_icon_->LoveStateChanged(false);
2019-06-12 00:38:52 +02:00
}
void MainWindow::PlaylistDelete() {
if (!delete_files_) return;
SongList selected_songs;
QStringList files;
bool is_current_item = false;
for (const QModelIndex &proxy_idx : ui_->playlist->view()->selectionModel()->selectedRows()) {
2022-08-09 17:23:46 +02:00
QModelIndex source_idx = app_->playlist_manager()->current()->filter()->mapToSource(proxy_idx);
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(source_idx.row());
if (!item || !item->Metadata().url().isLocalFile()) continue;
2022-02-05 15:56:01 +01:00
QString filename = item->Metadata().url().toLocalFile();
if (files.contains(filename)) continue;
selected_songs << item->Metadata();
2022-02-05 15:56:01 +01:00
files << filename;
if (item == app_->player()->GetCurrentItem()) is_current_item = true;
}
if (selected_songs.isEmpty()) return;
if (DeleteConfirmationDialog::warning(files) != QDialogButtonBox::Yes) return;
2023-04-22 19:13:42 +02:00
if (app_->player()->GetState() == EngineBase::State::Playing && app_->playlist_manager()->current()->rowCount() == selected_songs.count()) {
app_->player()->Stop();
}
ui_->playlist->view()->RemoveSelected();
2023-04-22 19:13:42 +02:00
if (app_->player()->GetState() == EngineBase::State::Playing && is_current_item) {
app_->player()->Next();
}
SharedPtr<MusicStorage> storage = make_shared<FilesystemMusicStorage>(Song::Source::LocalFile, "/");
DeleteFiles *delete_files = new DeleteFiles(app_->task_manager(), storage, true);
2021-01-26 16:48:04 +01:00
//QObject::connect(delete_files, &DeleteFiles::Finished, this, &MainWindow::DeleteFinished);
delete_files->Start(selected_songs);
}
void MainWindow::FocusSearchField() {
if (ui_->tabs->currentIndex() == ui_->tabs->IndexOfTab(collection_view_) && !collection_view_->filter_widget()->SearchFieldHasFocus()) {
collection_view_->filter_widget()->FocusSearchField();
}
#ifdef HAVE_SUBSONIC
else if (ui_->tabs->currentIndex() == ui_->tabs->IndexOfTab(subsonic_view_) && !subsonic_view_->SearchFieldHasFocus()) {
subsonic_view_->FocusSearchField();
}
#endif
#ifdef HAVE_TIDAL
else if (ui_->tabs->currentIndex() == ui_->tabs->IndexOfTab(tidal_view_) && !tidal_view_->SearchFieldHasFocus()) {
tidal_view_->FocusSearchField();
}
#endif
#ifdef HAVE_QOBUZ
else if (ui_->tabs->currentIndex() == ui_->tabs->IndexOfTab(qobuz_view_) && !qobuz_view_->SearchFieldHasFocus()) {
qobuz_view_->FocusSearchField();
}
#endif
2021-10-30 02:21:29 +02:00
else if (!ui_->playlist->SearchFieldHasFocus()) {
ui_->playlist->FocusSearchField();
}
}