diff --git a/ext/libclementine-common/core/lazy.h b/ext/libclementine-common/core/lazy.h index caf4235fb..ac65a8dee 100644 --- a/ext/libclementine-common/core/lazy.h +++ b/ext/libclementine-common/core/lazy.h @@ -41,6 +41,13 @@ class Lazy { T* operator->() const { return get(); } + // Returns true if the object is not yet initialised. + explicit operator bool() const { return ptr_; } + + // Deletes the underlying object and will re-run the initialisation function + // if the object is requested again. + void reset() { ptr_.reset(nullptr); } + private: void CheckInitialised() const { if (!ptr_) { diff --git a/ext/libclementine-common/core/logging.cpp b/ext/libclementine-common/core/logging.cpp index ec8faa267..2f9356dbc 100644 --- a/ext/libclementine-common/core/logging.cpp +++ b/ext/libclementine-common/core/logging.cpp @@ -25,6 +25,8 @@ #include #endif +#include + #include #include #include @@ -202,10 +204,11 @@ QDebug CreateLogger(Level level, const QString& class_name, int line) { } QDebug ret(type); - ret.nospace() << kMessageHandlerMagic << QDateTime::currentDateTime() - .toString("hh:mm:ss.zzz") - .toAscii() - .constData() << level_name + ret.nospace() << kMessageHandlerMagic + << QDateTime::currentDateTime() + .toString("hh:mm:ss.zzz") + .toAscii() + .constData() << level_name << function_line.leftJustified(32).toAscii().constData(); return ret.space(); @@ -257,7 +260,8 @@ void DumpStackTrace() { backtrace_symbols(reinterpret_cast(&callstack), callstack_size); // Start from 1 to skip ourself. for (int i = 1; i < callstack_size; ++i) { - qLog(Debug) << DemangleSymbol(QString::fromAscii(symbols[i])); + std::cerr << DemangleSymbol(QString::fromAscii(symbols[i])).toStdString() + << std::endl; } free(symbols); #else @@ -269,7 +273,7 @@ void DumpStackTrace() { namespace { -template +template QString print_duration(T duration, const std::string& unit) { return QString("%1%2").arg(duration.count()).arg(unit.c_str()); } diff --git a/src/core/application.cpp b/src/core/application.cpp index 1e902a3d4..8761704d8 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -21,29 +21,6 @@ */ #include "application.h" -#include "appearance.h" -#include "config.h" -#include "database.h" -#include "player.h" -#include "tagreaderclient.h" -#include "taskmanager.h" -#include "covers/albumcoverloader.h" -#include "covers/coverproviders.h" -#include "covers/currentartloader.h" -#include "devices/devicemanager.h" -#include "internet/core/internetmodel.h" -#include "globalsearch/globalsearch.h" -#include "library/library.h" -#include "library/librarybackend.h" -#include "networkremote/networkremote.h" -#include "networkremote/networkremotehelper.h" -#include "playlist/playlistbackend.h" -#include "playlist/playlistmanager.h" -#include "internet/podcasts/gpoddersync.h" -#include "internet/podcasts/podcastbackend.h" -#include "internet/podcasts/podcastdeleter.h" -#include "internet/podcasts/podcastdownloader.h" -#include "internet/podcasts/podcastupdater.h" #ifdef HAVE_LIBLASTFM #include "internet/lastfm/lastfmservice.h" @@ -58,95 +35,96 @@ bool Application::kIsPortable = false; Application::Application(QObject* parent) : QObject(parent), - tag_reader_client_(nullptr), - database_(nullptr), - album_cover_loader_(nullptr), - playlist_backend_(nullptr), - podcast_backend_(nullptr), - appearance_(nullptr), - cover_providers_(nullptr), - task_manager_(nullptr), - player_(nullptr), - playlist_manager_(nullptr), - current_art_loader_(nullptr), - global_search_(nullptr), - internet_model_(nullptr), - library_(nullptr), - device_manager_(nullptr), - podcast_updater_(nullptr), - podcast_deleter_(nullptr), - podcast_downloader_(nullptr), - gpodder_sync_(nullptr), - moodbar_loader_(nullptr), - moodbar_controller_(nullptr), - network_remote_(nullptr), - network_remote_helper_(nullptr), - scrobbler_(nullptr) { - tag_reader_client_ = new TagReaderClient(this); - MoveToNewThread(tag_reader_client_); - tag_reader_client_->Start(); - - database_ = new Database(this, this); - MoveToNewThread(database_); - - album_cover_loader_ = new AlbumCoverLoader(this); - MoveToNewThread(album_cover_loader_); - - playlist_backend_ = new PlaylistBackend(this, this); - MoveToThread(playlist_backend_, database_->thread()); - - podcast_backend_ = new PodcastBackend(this, this); - MoveToThread(podcast_backend_, database_->thread()); - - appearance_ = new Appearance(this); - cover_providers_ = new CoverProviders(this); - task_manager_ = new TaskManager(this); - player_ = new Player(this, this); - playlist_manager_ = new PlaylistManager(this, this); - current_art_loader_ = new CurrentArtLoader(this, this); - global_search_ = new GlobalSearch(this, this); - internet_model_ = new InternetModel(this, this); - library_ = new Library(this, this); - device_manager_ = new DeviceManager(this, this); - podcast_updater_ = new PodcastUpdater(this, this); - - podcast_deleter_ = new PodcastDeleter(this, this); - MoveToNewThread(podcast_deleter_); - - podcast_downloader_ = new PodcastDownloader(this, this); - gpodder_sync_ = new GPodderSync(this, this); - + tag_reader_client_([&](){ + TagReaderClient* client = new TagReaderClient(this); + MoveToNewThread(client); + client->Start(); + return client; + }), + database_([&]() { + Database* db = new Database(this, this); + MoveToNewThread(db); + DoInAMinuteOrSo(db, SLOT(DoBackup())); + return db; + }), + album_cover_loader_([&]() { + AlbumCoverLoader* loader = new AlbumCoverLoader(this); + MoveToNewThread(loader); + return loader; + }), + playlist_backend_([&]() { + PlaylistBackend* backend = new PlaylistBackend(this, this); + MoveToThread(backend, database_->thread()); + return backend; + }), + podcast_backend_([&]() { + PodcastBackend* backend = new PodcastBackend(this, this); + MoveToThread(backend, database_->thread()); + return backend; + }), + appearance_([=]() { return new Appearance(this); }), + cover_providers_([=]() { return new CoverProviders(this); }), + task_manager_([=]() { return new TaskManager(this); }), + player_([=]() { return new Player(this, this); }), + playlist_manager_([=]() { return new PlaylistManager(this); }), + current_art_loader_([=]() { return new CurrentArtLoader(this, this); }), + global_search_([=]() { return new GlobalSearch(this, this); }), + internet_model_([=]() { return new InternetModel(this, this); }), + library_([=]() { return new Library(this, this); }), + device_manager_([=]() { return new DeviceManager(this, this); }), + podcast_updater_([=]() { return new PodcastUpdater(this, this); }), + podcast_deleter_([=]() { + PodcastDeleter* deleter = new PodcastDeleter(this, this); + MoveToNewThread(deleter); + return deleter; + }), + podcast_downloader_([=]() { + return new PodcastDownloader(this, this); + }), + gpodder_sync_([=]() { return new GPodderSync(this, this); }), + moodbar_loader_([=]() { #ifdef HAVE_MOODBAR - moodbar_loader_ = new MoodbarLoader(this, this); - moodbar_controller_ = new MoodbarController(this, this); + return new MoodbarLoader(this, this); +#else + return nullptr; #endif - - // Network Remote - network_remote_ = new NetworkRemote(this); - MoveToNewThread(network_remote_); - - // This must be before libraray_->Init(); + }), + moodbar_controller_([=]() { +#ifdef HAVE_MOODBAR + return new MoodbarController(this, this); +#else + return nullptr; +#endif + }), + network_remote_([=]() { + NetworkRemote* remote = new NetworkRemote(this); + MoveToNewThread(remote); + return remote; + }), + network_remote_helper_([=]() { + return new NetworkRemoteHelper(this); + }), + scrobbler_([=]() { +#ifdef HAVE_LIBLASTFM + return new LastFMService(this, this); +#else + return nullptr; +#endif + }) { + // This must be before library_->Init(); // In the constructor the helper waits for the signal // PlaylistManagerInitialized // to start the remote. Without the playlist manager clementine can // crash when a client connects before the manager is initialized! - network_remote_helper_ = new NetworkRemoteHelper(this); - -#ifdef HAVE_LIBLASTFM - scrobbler_ = new LastFMService(this, this); -#endif // HAVE_LIBLASTFM - + network_remote_helper_.get(); library_->Init(); - - DoInAMinuteOrSo(database_, SLOT(DoBackup())); } Application::~Application() { // It's important that the device manager is deleted before the database. // Deleting the database deletes all objects that have been created in its // thread, including some device library backends. - delete device_manager_; - device_manager_ = nullptr; + device_manager_.reset(); for (QObject* object : objects_in_threads_) { object->deleteLater(); diff --git a/src/core/application.h b/src/core/application.h index 5157cb3ea..1f1d95215 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -22,37 +22,37 @@ #ifndef CORE_APPLICATION_H_ #define CORE_APPLICATION_H_ +#include "config.h" +#include "core/appearance.h" +#include "core/database.h" +#include "core/lazy.h" +#include "core/player.h" +#include "covers/albumcoverloader.h" +#include "covers/coverproviders.h" +#include "covers/currentartloader.h" +#include "devices/devicemanager.h" +#include "globalsearch/globalsearch.h" +#include "internet/core/internetmodel.h" +#include "internet/core/scrobbler.h" +#include "internet/podcasts/gpoddersync.h" +#include "internet/podcasts/podcastbackend.h" +#include "internet/podcasts/podcastdeleter.h" +#include "internet/podcasts/podcastdownloader.h" +#include "internet/podcasts/podcastupdater.h" +#include "library/librarybackend.h" +#include "library/library.h" +#include "moodbar/moodbarcontroller.h" +#include "moodbar/moodbarloader.h" +#include "networkremote/networkremote.h" +#include "networkremote/networkremotehelper.h" +#include "playlist/playlistbackend.h" +#include "playlist/playlistmanager.h" +#include "tagreaderclient.h" +#include "taskmanager.h" #include "ui/settingsdialog.h" #include -class AlbumCoverLoader; -class Appearance; -class CoverProviders; -class CurrentArtLoader; -class Database; -class DeviceManager; -class GlobalSearch; -class GPodderSync; -class InternetModel; -class Library; -class LibraryBackend; -class LibraryModel; -class MoodbarController; -class MoodbarLoader; -class NetworkRemote; -class NetworkRemoteHelper; -class Player; -class PlaylistBackend; -class PodcastDeleter; -class PodcastDownloader; -class PlaylistManager; -class PodcastBackend; -class PodcastUpdater; -class Scrobbler; -class TagReaderClient; -class TaskManager; - class Application : public QObject { Q_OBJECT @@ -68,32 +68,42 @@ class Application : public QObject { QString language_without_region() const; void set_language_name(const QString& name) { language_name_ = name; } - TagReaderClient* tag_reader_client() const { return tag_reader_client_; } - Database* database() const { return database_; } - AlbumCoverLoader* album_cover_loader() const { return album_cover_loader_; } - PlaylistBackend* playlist_backend() const { return playlist_backend_; } - PodcastBackend* podcast_backend() const { return podcast_backend_; } - Appearance* appearance() const { return appearance_; } - CoverProviders* cover_providers() const { return cover_providers_; } - TaskManager* task_manager() const { return task_manager_; } - Player* player() const { return player_; } - PlaylistManager* playlist_manager() const { return playlist_manager_; } - CurrentArtLoader* current_art_loader() const { return current_art_loader_; } - GlobalSearch* global_search() const { return global_search_; } - InternetModel* internet_model() const { return internet_model_; } - Library* library() const { return library_; } - DeviceManager* device_manager() const { return device_manager_; } - PodcastUpdater* podcast_updater() const { return podcast_updater_; } - PodcastDeleter* podcast_deleter() const { return podcast_deleter_; } - PodcastDownloader* podcast_downloader() const { return podcast_downloader_; } - GPodderSync* gpodder_sync() const { return gpodder_sync_; } - MoodbarLoader* moodbar_loader() const { return moodbar_loader_; } - MoodbarController* moodbar_controller() const { return moodbar_controller_; } - NetworkRemote* network_remote() const { return network_remote_; } - NetworkRemoteHelper* network_remote_helper() const { - return network_remote_helper_; + TagReaderClient* tag_reader_client() const { + return tag_reader_client_.get(); } - Scrobbler* scrobbler() const { return scrobbler_; } + Database* database() const { return database_.get(); } + AlbumCoverLoader* album_cover_loader() const { + return album_cover_loader_.get(); + } + PlaylistBackend* playlist_backend() const { return playlist_backend_.get(); } + PodcastBackend* podcast_backend() const { return podcast_backend_.get(); } + Appearance* appearance() const { return appearance_.get(); } + CoverProviders* cover_providers() const { return cover_providers_.get(); } + TaskManager* task_manager() const { return task_manager_.get(); } + Player* player() const { return player_.get(); } + PlaylistManager* playlist_manager() const { return playlist_manager_.get(); } + CurrentArtLoader* current_art_loader() const { + return current_art_loader_.get(); + } + GlobalSearch* global_search() const { return global_search_.get(); } + InternetModel* internet_model() const { return internet_model_.get(); } + Library* library() const { return library_.get(); } + DeviceManager* device_manager() const { return device_manager_.get(); } + PodcastUpdater* podcast_updater() const { return podcast_updater_.get(); } + PodcastDeleter* podcast_deleter() const { return podcast_deleter_.get(); } + PodcastDownloader* podcast_downloader() const { + return podcast_downloader_.get(); + } + GPodderSync* gpodder_sync() const { return gpodder_sync_.get(); } + MoodbarLoader* moodbar_loader() const { return moodbar_loader_.get(); } + MoodbarController* moodbar_controller() const { + return moodbar_controller_.get(); + } + NetworkRemote* network_remote() const { return network_remote_.get(); } + NetworkRemoteHelper* network_remote_helper() const { + return network_remote_helper_.get(); + } + Scrobbler* scrobbler() const { return scrobbler_.get(); } LibraryBackend* library_backend() const; LibraryModel* library_model() const; @@ -106,7 +116,7 @@ class Application : public QObject { void ReloadSettings(); void OpenSettingsDialogAtPage(SettingsDialog::Page page); - signals: +signals: void ErrorAdded(const QString& message); void SettingsChanged(); void SettingsDialogRequested(SettingsDialog::Page page); @@ -114,30 +124,30 @@ class Application : public QObject { private: QString language_name_; - TagReaderClient* tag_reader_client_; - Database* database_; - AlbumCoverLoader* album_cover_loader_; - PlaylistBackend* playlist_backend_; - PodcastBackend* podcast_backend_; - Appearance* appearance_; - CoverProviders* cover_providers_; - TaskManager* task_manager_; - Player* player_; - PlaylistManager* playlist_manager_; - CurrentArtLoader* current_art_loader_; - GlobalSearch* global_search_; - InternetModel* internet_model_; - Library* library_; - DeviceManager* device_manager_; - PodcastUpdater* podcast_updater_; - PodcastDeleter* podcast_deleter_; - PodcastDownloader* podcast_downloader_; - GPodderSync* gpodder_sync_; - MoodbarLoader* moodbar_loader_; - MoodbarController* moodbar_controller_; - NetworkRemote* network_remote_; - NetworkRemoteHelper* network_remote_helper_; - Scrobbler* scrobbler_; + Lazy tag_reader_client_; + Lazy database_; + Lazy album_cover_loader_; + Lazy playlist_backend_; + Lazy podcast_backend_; + Lazy appearance_; + Lazy cover_providers_; + Lazy task_manager_; + Lazy player_; + Lazy playlist_manager_; + Lazy current_art_loader_; + Lazy global_search_; + Lazy internet_model_; + Lazy library_; + Lazy device_manager_; + Lazy podcast_updater_; + Lazy podcast_deleter_; + Lazy podcast_downloader_; + Lazy gpodder_sync_; + Lazy moodbar_loader_; + Lazy moodbar_controller_; + Lazy network_remote_; + Lazy network_remote_helper_; + Lazy scrobbler_; QList objects_in_threads_; QList threads_; diff --git a/src/networkremote/networkremote.cpp b/src/networkremote/networkremote.cpp index a45dc81be..0ec86e454 100644 --- a/src/networkremote/networkremote.cpp +++ b/src/networkremote/networkremote.cpp @@ -17,15 +17,18 @@ #include "networkremote.h" -#include "core/logging.h" -#include "covers/currentartloader.h" -#include "networkremote/zeroconf.h" -#include "playlist/playlistmanager.h" - #include #include #include #include +#include + +#include "core/logging.h" +#include "covers/currentartloader.h" +#include "networkremote/incomingdataparser.h" +#include "networkremote/outgoingdatacreator.h" +#include "networkremote/zeroconf.h" +#include "playlist/playlistmanager.h" const char* NetworkRemote::kSettingsGroup = "NetworkRemote"; const quint16 NetworkRemote::kDefaultServerPort = 5500; diff --git a/src/networkremote/networkremote.h b/src/networkremote/networkremote.h index 9f53b0f5a..9f550f02d 100644 --- a/src/networkremote/networkremote.h +++ b/src/networkremote/networkremote.h @@ -3,14 +3,17 @@ #include -#include -#include +#include +#include -#include "core/player.h" -#include "core/application.h" -#include "incomingdataparser.h" -#include "outgoingdatacreator.h" -#include "remoteclient.h" +class Application; +class IncomingDataParser; +class OutgoingDataCreator; +class QHostAddress; +class QImage; +class QTcpServer; +class QTcpSocket; +class RemoteClient; class NetworkRemote : public QObject { Q_OBJECT diff --git a/src/networkremote/networkremotehelper.cpp b/src/networkremote/networkremotehelper.cpp index 6c7496555..0e9e04451 100644 --- a/src/networkremote/networkremotehelper.cpp +++ b/src/networkremote/networkremotehelper.cpp @@ -15,10 +15,11 @@ along with Clementine. If not, see . */ -#include "core/logging.h" +#include "networkremote/networkremotehelper.h" -#include "networkremote.h" -#include "networkremotehelper.h" +#include "core/application.h" +#include "core/logging.h" +#include "networkremote/networkremote.h" NetworkRemoteHelper* NetworkRemoteHelper::sInstance = nullptr; diff --git a/src/networkremote/songsender.cpp b/src/networkremote/songsender.cpp index 43fb945b7..e06b2933b 100644 --- a/src/networkremote/songsender.cpp +++ b/src/networkremote/songsender.cpp @@ -17,14 +17,15 @@ #include "songsender.h" -#include "networkremote.h" - #include #include "core/application.h" #include "core/logging.h" #include "core/utilities.h" #include "library/librarybackend.h" +#include "networkremote/networkremote.h" +#include "networkremote/outgoingdatacreator.h" +#include "networkremote/remoteclient.h" #include "playlist/playlistitem.h" const quint32 SongSender::kFileChunkSize = 100000; // in Bytes @@ -32,16 +33,18 @@ const quint32 SongSender::kFileChunkSize = 100000; // in Bytes SongSender::SongSender(Application* app, RemoteClient* client) : app_(app), client_(client), - transcoder_(new Transcoder(this, NetworkRemote::kTranscoderSettingPostfix)) { + transcoder_( + new Transcoder(this, NetworkRemote::kTranscoderSettingPostfix)) { QSettings s; s.beginGroup(NetworkRemote::kSettingsGroup); transcode_lossless_files_ = s.value("convert_lossless", false).toBool(); // Load preset - QString last_output_format = s.value("last_output_format", "audio/x-vorbis").toString(); + QString last_output_format = + s.value("last_output_format", "audio/x-vorbis").toString(); QList presets = transcoder_->GetAllPresets(); - for (int i = 0; iCancel(); } @@ -102,8 +106,7 @@ void SongSender::SendSongs(const pb::remote::RequestDownloadSongs& request) { void SongSender::TranscodeLosslessFiles() { for (DownloadItem item : download_queue_) { // Check only lossless files - if (!item.song_.IsFileLossless()) - continue; + if (!item.song_.IsFileLossless()) continue; // Add the file to the transcoder QString local_file = item.song_.url().toLocalFile(); @@ -122,7 +125,8 @@ void SongSender::TranscodeLosslessFiles() { } } -void SongSender::TranscodeJobComplete(const QString& input, const QString& output, bool success) { +void SongSender::TranscodeJobComplete(const QString& input, + const QString& output, bool success) { qLog(Debug) << input << "transcoded to" << output << success; // If it wasn't successful send original file @@ -204,7 +208,8 @@ void SongSender::OfferNextSong() { chunk->set_file_number(item.song_no_); chunk->set_size(file.size()); - OutgoingDataCreator::CreateSong(item.song_, QImage(), -1, chunk->mutable_song_metadata()); + OutgoingDataCreator::CreateSong(item.song_, QImage(), -1, + chunk->mutable_song_metadata()); } client_->SendData(&msg); @@ -215,8 +220,7 @@ void SongSender::ResponseSongOffer(bool accepted) { // Get the item and send the single song DownloadItem item = download_queue_.dequeue(); - if (accepted) - SendSingleSong(item); + if (accepted) SendSingleSong(item); // And offer the next song OfferNextSong(); @@ -273,7 +277,8 @@ void SongSender::SendSingleSong(DownloadItem download_item) { int i = app_->playlist_manager()->active()->current_row(); pb::remote::SongMetadata* song_metadata = msg.mutable_response_song_file_chunk()->mutable_song_metadata(); - OutgoingDataCreator::CreateSong(download_item.song_, null_image, i,song_metadata); + OutgoingDataCreator::CreateSong(download_item.song_, null_image, i, + song_metadata); // if the file was transcoded, we have to change the filename and filesize if (is_transcoded) { @@ -341,7 +346,7 @@ void SongSender::SendPlaylist(int playlist_id) { } } -void SongSender::SendUrls(const pb::remote::RequestDownloadSongs &request) { +void SongSender::SendUrls(const pb::remote::RequestDownloadSongs& request) { SongList song_list; // First gather all valid songs diff --git a/src/ui/networkremotesettingspage.cpp b/src/ui/networkremotesettingspage.cpp index e80811bf5..422162744 100644 --- a/src/ui/networkremotesettingspage.cpp +++ b/src/ui/networkremotesettingspage.cpp @@ -15,18 +15,23 @@ along with Clementine. If not, see . */ -#include "iconloader.h" #include "networkremotesettingspage.h" #include "ui_networkremotesettingspage.h" + +#include +#include +#include +#include +#include +#include + +#include "core/application.h" #include "networkremote/networkremote.h" #include "networkremote/networkremotehelper.h" #include "transcoder/transcoder.h" #include "transcoder/transcoderoptionsdialog.h" - -#include -#include -#include -#include +#include "ui/iconloader.h" +#include "ui/settingsdialog.h" const char* NetworkRemoteSettingsPage::kPlayStoreUrl = "https://play.google.com/store/apps/details?id=de.qspool.clementineremote"; @@ -83,10 +88,12 @@ void NetworkRemoteSettingsPage::Load() { ui_->auth_code->setValue(s.value("auth_code", qrand() % 100000).toInt()); ui_->allow_downloads->setChecked(s.value("allow_downloads", false).toBool()); - ui_->convert_lossless->setChecked(s.value("convert_lossless", false).toBool()); + ui_->convert_lossless->setChecked( + s.value("convert_lossless", false).toBool()); // Load settings - QString last_output_format = s.value("last_output_format", "audio/x-vorbis").toString(); + QString last_output_format = + s.value("last_output_format", "audio/x-vorbis").toString(); for (int i = 0; i < ui_->format->count(); ++i) { if (last_output_format == ui_->format->itemData(i).value().codec_mimetype_) {