From 46d9b22a79cb8e99a8141ec0a0a143f0aa701401 Mon Sep 17 00:00:00 2001 From: Be Date: Wed, 22 Apr 2020 21:55:40 -0500 Subject: [PATCH 001/194] CONTRIBUTING.md: move content from DocuWiki This content was at https://mixxx.org/wiki/doku.php/contribution_guidelines but not many developers saw it. The conventional place for such documents is a CONTRIBUTING.md file in the Git repository. --- CONTRIBUTING.md | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..ccfc1b10199 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,86 @@ +# Mixxx Contribution Guidelines # +Thank you for contributing to [Mixxx](https://mixxx.org/)! Your work helps DJs all over the world! We are global, all volunteer team that works by consensus and we are excited to have you join us. This document specifies technical aspects of our workflow. For social aspects please refer to [CODE_OF_CONDUCT.md](https://github.com/mixxxdj/mixxx/blob/master/CODE_OF_CONDUCT.md) in this repository. We encourage you to introduce yourself on our [Zulip chat](https://mixxx.zulipchat.com/) before starting to contribute code to Mixxx. + +Table of Contents +1. [Orientation](#Orientation) + 1. [Git Repositories](#Git-Repositories) +2. [Git Workflow](#Git-Workflow) + 1. [All Contributors](#All-Contributors) + 2. [Core Team](#Core-Team) + +## Orientation ## +We have lots more helpful information for users and developers on the [Mixxx wiki](https://mixxx.org/wiki/doku.php/start), including [build instructions](https://mixxx.org/wiki/doku.php/start#compile_mixxx_from_source_code). + +### Git Repositories ### +This repository contains the Mixxx source code, skins, controller mappings, and some helpful scripts. We have a few other Git repositories too: +* [mixxxdj/website](https://github.com/mixxxdj/website): content for the main [mixxx.org](https://mixxx.org/) website which is generated with the [Cactus static site generator](https://github.com/eudicots/Cactus) +* [mixxxdj/manual](https://github.com/mixxxdj/manual): content for the Mixxx manual, which uses [Sphinx](https://www.sphinx-doc.org/) +* [mixxxdj/buildserver](https://github.com/mixxxdj/buildserver): scripts for generating our prebuilt dependencies for macOS and Windows + +All of these are automatically built and deployed by our [Jenkins build servers](https://builds.renegadetech.mixxx.org/) whenever a change is committed. Anyone is welcome to open a pull request for all of these repositories. + +## Git Workflow ## +### All Contributors ### +* Each feature/bug fix should be done on its own Git branch so they can be reviewed and merged independently. Refer to [Using Git](https://mixxx.org/wiki/doku.php/using_git) for how to do this. Please ask for help on [Zulip](https://mixxx.zulipchat.com/) if you have questions about using Git after reading that page. +* Commits should be as small as they can while still building. The smaller the commit, the easier it is to review. It also makes it easier to revert if it is later identified as the source of a bug. If you have lots of changes that you need to commit, a [GUI Git client](https://git-scm.com/downloads/guis) can be helpful for picking out specific changes for multiple small commits. +* Every commit should build. This is important so [git bisect](https://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git#_binary_search) works. +* Commit messages should succinctly describe what is changed in that commit and why. Lines should wrap at 72 characters so they show fully in GitHub and other Git tools. For example, this is a good commit message: + + ``` + DlgPrefEffects: add QListWidget to set order of chains + + This order will soon be used by new ControlObjects to load them + from controllers. + ``` + + This is not a good commit message: + + ``` + address comments from PR review + ``` + + Neither is this: + + ``` + fix a bug with quantize while the deck is playing and master sync is enabled and an effect unit is on the deck while the user is turning an EQ knob + ``` + + Refer to [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/) for more details. + +* Install [pre-commit](https://pre-commit.com/#install) to automatically ensure that your commits comply with our code style for both C++ and JavaScript. Note this is currently not working on Windows. This saves time reviewing so we don't have to point out nitpicky style issues. Once you have pre-commit installed on your computer, set it up in your local Git repository: + + ``` + cd /path/to/your/git/repo + pre-commit install + pre-commit install -t pre-push + ``` + + If you have a problems with a particular hook, you can use the SKIP environment variable to disable hooks: + + ``` + SKIP=clang-format,end-of-file-fixer git commit + ``` + + This can also be used to separate logic changes and autoformatting into two subsequent commits. Using the SKIP environment variable is preferable to using `git commit --no-verify` (which also disables the checks) because it won't prevent catching other, unrelated issues. + +* Generally, prefer merging to rebasing. Do not rebase unless you have discussed that with whoever is reviewing the pull request. When you rebase a branch with an open pull request, prior review comments made inline in the code on GitHub lose their connection to that spot in the code. If you want to correct minor mistakes with a rebase or `git commit --amend` within a few minutes of pushing commits, that is okay as long as no one has started reviewing those commits yet. +* If you are helping with someone else's pull request that is not yet merged, open a pull request targeted at their fork. Leave a comment on the upstream pull request (which targets mixxxdj/mixxx) with a link to your pull request so other Mixxx contributors are aware of your changes. +* Low risk bug fixes should be targeted at the stable branch (currently 2.2). However, bug fixes for the stable branches must have a direct impact on users. If you spot a minor bug reading the code or only want to clean up the code, target that at the master or beta branch. +* Controller mappings should be targeted at the stable branch unless they use features that are new in the beta or master branch. +* If you are making changes to the GUI with a pull request, please post before and after screenshots of the changes. +* Please help review other people's pull requests. When others review your pull requests, please return the favor. The continued progress of Mixxx depends on all of us working together. Even if you are not familiar with the area of the code being changed in a pull request, you can be helpful by building the branch, verifying that it works as described, and commenting with feedback about the user experience design. +* If you demonstrate good coding skills, help review pull requests, contribute major features, and show a commitment to Mixxx over time, we may invite you to the core team. + +### Core Team ### +Mixxx core team members are contributors who have write access to the [upstream mixxxdj repositories](https://github.com/mixxxdj/) on GitHub, access to the Jenkins web interface for the build servers, and access to the private Zulip stream for the core team. + +* Enable [two-factor authentication (2FA)](https://help.github.com/en/github/authenticating-to-github/securing-your-account-with-two-factor-authentication-2fa) for your GitHub account. +* _Never_ force push to an upstream repository (mixxxdj). If you encounter an error from Git saying you would need to force push, stop what you are doing and discuss the situation on Zulip. +* Only push directly to an upstream repository (mixxxdj) for trivial, uncontroversial changes like fixing a typo. +* All non-trivial contributions should be made with a pull request, just like any other contributor who does not have write access. Do not merge your own pull requests. +* You may merge someone else's pull request as the only reviewer if no other contributors have expressed concerns about the changes or said they want to review the code. Please do not merge pull requests immediately; allow at least a day or two for others to comment. Remember we are all volunteers and cannot respond to everything immediately. +* If there is disagreement about changes in a pull request, do not merge it until a consensus has been reached. +* Check CI to ensure builds work and tests pass before merging. If CI timed out, either manually restart it or build the branch and run the tests locally before merging. +* When you merge a pull request to a stable branch, merge the stable branch to the beta branch afterwards. If you merge a pull request to a beta branch, merge the beta branch to master afterwards. When backporting, cherry-pick or rebase rather than merge. +* Default to open; only post in the private Zulip stream for discussions that have a reason to be private. Most of the time, post to a public Zulip stream so anyone can participate in the discussion. +* When Mixxx participates in Google Summer of Code, you may volunteer as a mentor if you like. From 90c7b264339d7cdfe0fb3dacf0b22e4f5dd8f2ed Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 19 May 2020 15:04:57 -0500 Subject: [PATCH 002/194] CONTRIBUTING.md: directly address the reader Co-authored-by: Janek --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ccfc1b10199..f9a639a6c2f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ This repository contains the Mixxx source code, skins, controller mappings, and * [mixxxdj/manual](https://github.com/mixxxdj/manual): content for the Mixxx manual, which uses [Sphinx](https://www.sphinx-doc.org/) * [mixxxdj/buildserver](https://github.com/mixxxdj/buildserver): scripts for generating our prebuilt dependencies for macOS and Windows -All of these are automatically built and deployed by our [Jenkins build servers](https://builds.renegadetech.mixxx.org/) whenever a change is committed. Anyone is welcome to open a pull request for all of these repositories. +All of these are automatically built and deployed by our [Jenkins build servers](https://builds.renegadetech.mixxx.org/) whenever a change is committed. You are welcome to open a pull request in any of these repositories. ## Git Workflow ## ### All Contributors ### From 1bcdbb753f840e6e24783b7bba4a732985a58ef9 Mon Sep 17 00:00:00 2001 From: ehmic <1mail4me@web.de> Date: Wed, 16 Jun 2021 14:15:24 +0200 Subject: [PATCH 003/194] Reordered Musicbrainz tags (in columns) as suggested in lp1924620 + lp1899350 --- src/library/dlgtagfetcher.cpp | 30 ++++++++++++++++-------------- src/library/dlgtagfetcher.ui | 14 +++++++------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/library/dlgtagfetcher.cpp b/src/library/dlgtagfetcher.cpp index 8947763ebb0..2caeb84a8ec 100644 --- a/src/library/dlgtagfetcher.cpp +++ b/src/library/dlgtagfetcher.cpp @@ -19,12 +19,12 @@ QStringList trackColumnValues( QStringList columnValues; columnValues.reserve(6); columnValues - << trackMetadata.getTrackInfo().getYear() + << trackMetadata.getTrackInfo().getTitle() + << trackMetadata.getTrackInfo().getArtist() << trackMetadata.getAlbumInfo().getTitle() - << trackMetadata.getAlbumInfo().getArtist() + << trackMetadata.getTrackInfo().getYear() << trackNumberAndTotal - << trackMetadata.getTrackInfo().getTitle() - << trackMetadata.getTrackInfo().getArtist(); + << trackMetadata.getAlbumInfo().getArtist(); return columnValues; } @@ -36,12 +36,14 @@ QStringList trackReleaseColumnValues( QStringList columnValues; columnValues.reserve(6); columnValues - << trackRelease.date + << trackRelease.title + << trackRelease.artist << trackRelease.albumTitle - << trackRelease.albumArtist + << trackRelease.date << trackNumberAndTotal - << trackRelease.title - << trackRelease.artist; + << trackRelease.albumArtist + + ; return columnValues; } @@ -86,12 +88,12 @@ void DlgTagFetcher::init() { connect(&m_tagFetcher, &TagFetcher::networkError, this, &DlgTagFetcher::slotNetworkResult); // Resize columns, this can't be set in the ui file - results->setColumnWidth(0, 50); // Year column - results->setColumnWidth(1, 160); // Album column - results->setColumnWidth(2, 160); // Album artist column - results->setColumnWidth(3, 50); // Track (numbers) column - results->setColumnWidth(4, 160); // Title column - results->setColumnWidth(5, 160); // Artist column + results->setColumnWidth(0, 160); // Title column + results->setColumnWidth(1, 160); // Artist column + results->setColumnWidth(2, 160); // Album column + results->setColumnWidth(3, 50); // Year column + results->setColumnWidth(4, 50); // Track (numbers) column + results->setColumnWidth(5, 160); // Album artist column } void DlgTagFetcher::slotNext() { diff --git a/src/library/dlgtagfetcher.ui b/src/library/dlgtagfetcher.ui index 471061db12a..1f589d29812 100644 --- a/src/library/dlgtagfetcher.ui +++ b/src/library/dlgtagfetcher.ui @@ -17,7 +17,7 @@ - 2 + 0 @@ -47,32 +47,32 @@ - Year + Title - Album + Artist - Album Artist + Album - Track + Year - Title + Track - Artist + Album Artist From 8b38a55c156b577d9effbdb10526ec5efd96b5ee Mon Sep 17 00:00:00 2001 From: ehmic <1mail4me@web.de> Date: Mon, 21 Jun 2021 15:14:38 +0200 Subject: [PATCH 004/194] Made the columns resize to their contents - attribute headerStretchLastSection=false is required for the last column to be resized properly, too --- src/library/dlgtagfetcher.cpp | 4 +++- src/library/dlgtagfetcher.ui | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/library/dlgtagfetcher.cpp b/src/library/dlgtagfetcher.cpp index 2caeb84a8ec..c7b593b9a40 100644 --- a/src/library/dlgtagfetcher.cpp +++ b/src/library/dlgtagfetcher.cpp @@ -53,7 +53,7 @@ void addTrack( QTreeWidget* parent) { QTreeWidgetItem* item = new QTreeWidgetItem(parent, trackRow); item->setData(0, Qt::UserRole, resultIndex); - item->setData(0, Qt::TextAlignmentRole, Qt::AlignRight); + item->setData(0, Qt::TextAlignmentRole, Qt::AlignLeft); } } // anonymous namespace @@ -309,6 +309,8 @@ void DlgTagFetcher::updateStack() { } } + results->header()->resizeSections(QHeaderView::ResizeToContents); + // Find the item that was selected last time for (int i = 0; i < results->model()->rowCount(); ++i) { const QModelIndex index = results->model()->index(i, 0); diff --git a/src/library/dlgtagfetcher.ui b/src/library/dlgtagfetcher.ui index 1f589d29812..01b9f27da08 100644 --- a/src/library/dlgtagfetcher.ui +++ b/src/library/dlgtagfetcher.ui @@ -45,6 +45,9 @@ 50 + + false + Title From a4c9d6a177573c8c4dd1b5960735e67a8b563281 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 22 Jun 2021 17:50:02 +0200 Subject: [PATCH 005/194] LibraryFeature: Rename getChildModel to sidebarModel and make it const --- src/library/analysisfeature.cpp | 15 ++++++----- src/library/analysisfeature.h | 4 +-- src/library/autodj/autodjfeature.cpp | 23 ++++++++-------- src/library/autodj/autodjfeature.h | 4 +-- src/library/banshee/bansheefeature.cpp | 7 ++--- src/library/banshee/bansheefeature.h | 4 +-- src/library/browse/browsefeature.cpp | 19 ++++++------- src/library/browse/browsefeature.h | 4 +-- src/library/itunes/itunesfeature.cpp | 7 ++--- src/library/itunes/itunesfeature.h | 4 +-- src/library/libraryfeature.h | 2 +- src/library/mixxxlibraryfeature.cpp | 7 ++--- src/library/mixxxlibraryfeature.h | 4 +-- src/library/recording/recordingfeature.cpp | 11 ++++---- src/library/recording/recordingfeature.h | 4 +-- src/library/rekordbox/rekordboxfeature.cpp | 17 ++++++------ src/library/rekordbox/rekordboxfeature.h | 4 +-- src/library/rhythmbox/rhythmboxfeature.cpp | 7 ++--- src/library/rhythmbox/rhythmboxfeature.h | 4 +-- src/library/serato/seratofeature.cpp | 17 ++++++------ src/library/serato/seratofeature.h | 4 +-- src/library/sidebarmodel.cpp | 10 +++---- src/library/trackset/baseplaylistfeature.cpp | 26 +++++++++--------- src/library/trackset/baseplaylistfeature.h | 2 +- src/library/trackset/basetracksetfeature.cpp | 3 ++- src/library/trackset/basetracksetfeature.h | 2 +- src/library/trackset/crate/cratefeature.cpp | 28 ++++++++++---------- src/library/trackset/crate/cratefeature.h | 2 +- src/library/trackset/playlistfeature.cpp | 6 ++--- src/library/trackset/setlogfeature.cpp | 4 +-- src/library/traktor/traktorfeature.cpp | 7 ++--- src/library/traktor/traktorfeature.h | 4 +-- 32 files changed, 139 insertions(+), 127 deletions(-) diff --git a/src/library/analysisfeature.cpp b/src/library/analysisfeature.cpp index 6de7480371f..074742427d8 100644 --- a/src/library/analysisfeature.cpp +++ b/src/library/analysisfeature.cpp @@ -49,11 +49,12 @@ AnalysisFeature::AnalysisFeature( Library* pLibrary, UserSettingsPointer pConfig) : LibraryFeature(pLibrary, pConfig), - m_baseTitle(tr("Analyze")), - m_icon(":/images/library/ic_library_prepare.svg"), - m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), - m_pAnalysisView(nullptr), - m_title(m_baseTitle) { + m_baseTitle(tr("Analyze")), + m_icon(":/images/library/ic_library_prepare.svg"), + m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), + m_pSidebarModel(new TreeItemModel(this)), + m_pAnalysisView(nullptr), + m_title(m_baseTitle) { } void AnalysisFeature::resetTitle() { @@ -111,8 +112,8 @@ void AnalysisFeature::bindLibraryWidget(WLibrary* libraryWidget, libraryWidget->registerView(kViewName, m_pAnalysisView); } -TreeItemModel* AnalysisFeature::getChildModel() { - return &m_childModel; +TreeItemModel* AnalysisFeature::sidebarModel() const { + return m_pSidebarModel; } void AnalysisFeature::refreshLibraryModels() { diff --git a/src/library/analysisfeature.h b/src/library/analysisfeature.h index f9a60047c12..b447ce36e7a 100644 --- a/src/library/analysisfeature.h +++ b/src/library/analysisfeature.h @@ -35,7 +35,7 @@ class AnalysisFeature : public LibraryFeature { void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; void refreshLibraryModels(); signals: @@ -68,7 +68,7 @@ class AnalysisFeature : public LibraryFeature { TrackAnalysisScheduler::Pointer m_pTrackAnalysisScheduler; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; DlgAnalysis* m_pAnalysisView; // The title is dynamic and reflects the current progress diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index af4a685be9e..fc4b2748b26 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -53,6 +53,7 @@ AutoDJFeature::AutoDJFeature(Library* pLibrary, m_playlistDao(m_pTrackCollection->getPlaylistDAO()), m_iAutoDJPlaylistId(findOrCrateAutoDjPlaylistId(m_playlistDao)), m_pAutoDJProcessor(nullptr), + m_pSidebarModel(new TreeItemModel(this)), m_pAutoDJView(nullptr), m_autoDjCratesDao(m_iAutoDJPlaylistId, pLibrary->trackCollectionManager(), m_pConfig), m_icon(":/images/library/ic_library_autodj.svg") { @@ -76,7 +77,7 @@ AutoDJFeature::AutoDJFeature(Library* pLibrary, // Create tree-items under "Crates". constructCrateChildModel(); - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); // Be notified when the status of crates changes. connect(m_pTrackCollection, @@ -154,8 +155,8 @@ void AutoDJFeature::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) { m_pSidebarWidget = pSidebarWidget; } -TreeItemModel* AutoDJFeature::getChildModel() { - return &m_childModel; +TreeItemModel* AutoDJFeature::sidebarModel() const { + return m_pSidebarModel; } void AutoDJFeature::activate() { @@ -204,9 +205,9 @@ void AutoDJFeature::slotCrateChanged(CrateId crateId) { // -> Find and update the corresponding child item for (int i = 0; i < m_crateList.length(); ++i) { if (m_crateList[i].getId() == crateId) { - QModelIndex parentIndex = m_childModel.index(0, 0); - QModelIndex childIndex = m_childModel.index(i, 0, parentIndex); - m_childModel.setData(childIndex, crate.getName(), Qt::DisplayRole); + QModelIndex parentIndex = m_pSidebarModel->index(0, 0); + QModelIndex childIndex = m_pSidebarModel->index(i, 0, parentIndex); + m_pSidebarModel->setData(childIndex, crate.getName(), Qt::DisplayRole); m_crateList[i] = crate; return; // early exit } @@ -215,17 +216,17 @@ void AutoDJFeature::slotCrateChanged(CrateId crateId) { // -> Create and append a new child item for this crate QList rows; rows.append(new TreeItem(crate.getName(), crate.getId().toVariant())); - QModelIndex parentIndex = m_childModel.index(0, 0); - m_childModel.insertTreeItemRows(rows, m_crateList.length(), parentIndex); - DEBUG_ASSERT(rows.isEmpty()); // ownership passed to m_childModel + QModelIndex parentIndex = m_pSidebarModel->index(0, 0); + m_pSidebarModel->insertTreeItemRows(rows, m_crateList.length(), parentIndex); + DEBUG_ASSERT(rows.isEmpty()); // ownership passed to m_pSidebarModel m_crateList.append(crate); } else { // Crate does not exist or is not a source for AutoDJ // -> Find and remove the corresponding child item for (int i = 0; i < m_crateList.length(); ++i) { if (m_crateList[i].getId() == crateId) { - QModelIndex parentIndex = m_childModel.index(0, 0); - m_childModel.removeRows(i, 1, parentIndex); + QModelIndex parentIndex = m_pSidebarModel->index(0, 0); + m_pSidebarModel->removeRows(i, 1, parentIndex); m_crateList.removeAt(i); return; // early exit } diff --git a/src/library/autodj/autodjfeature.h b/src/library/autodj/autodjfeature.h index c6f3ef12a72..7148674a922 100644 --- a/src/library/autodj/autodjfeature.h +++ b/src/library/autodj/autodjfeature.h @@ -43,7 +43,7 @@ class AutoDJFeature : public LibraryFeature { KeyboardEventFilter* keyboard) override; void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; bool hasTrackTable() override { return true; @@ -62,7 +62,7 @@ class AutoDJFeature : public LibraryFeature { // The id of the AutoDJ playlist. int m_iAutoDJPlaylistId; AutoDJProcessor* m_pAutoDJProcessor; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; DlgAutoDJ* m_pAutoDJView; // Initialize the list of crates loaded into the auto-DJ queue. diff --git a/src/library/banshee/bansheefeature.cpp b/src/library/banshee/bansheefeature.cpp index 800b5bd7fa2..dcba9297904 100644 --- a/src/library/banshee/bansheefeature.cpp +++ b/src/library/banshee/bansheefeature.cpp @@ -18,6 +18,7 @@ QString BansheeFeature::m_databaseFile; BansheeFeature::BansheeFeature(Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), + m_pSidebarModel(new TreeItemModel(this)), m_cancelImport(false), m_icon(":/images/library/ic_library_banshee.svg") { Q_UNUSED(pConfig); @@ -102,7 +103,7 @@ void BansheeFeature::activate() { // append the playlist to the child model pRootItem->appendChild(playlist.name, playlist.playlistId); } - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); if (m_isActivated) { activate(); @@ -130,8 +131,8 @@ void BansheeFeature::activateChild(const QModelIndex& index) { } } -TreeItemModel* BansheeFeature::getChildModel() { - return &m_childModel; +TreeItemModel* BansheeFeature::sidebarModel() const { + return m_pSidebarModel; } void BansheeFeature::appendTrackIdsFromRightClickIndex(QList* trackIds, QString* pPlaylist) { diff --git a/src/library/banshee/bansheefeature.h b/src/library/banshee/bansheefeature.h index 46e9bcf695c..ce08d717812 100644 --- a/src/library/banshee/bansheefeature.h +++ b/src/library/banshee/bansheefeature.h @@ -26,7 +26,7 @@ class BansheeFeature : public BaseExternalLibraryFeature { virtual QVariant title(); virtual QIcon getIcon(); - virtual TreeItemModel* getChildModel(); + virtual TreeItemModel* sidebarModel() const; public slots: virtual void activate(); @@ -36,7 +36,7 @@ class BansheeFeature : public BaseExternalLibraryFeature { virtual void appendTrackIdsFromRightClickIndex(QList* trackIds, QString* pPlaylist); BansheePlaylistModel* m_pBansheePlaylistModel; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; QStringList m_playlists; //a new DB connection for the worker thread diff --git a/src/library/browse/browsefeature.cpp b/src/library/browse/browsefeature.cpp index 66c375c3fbb..3b1f2a7d30b 100644 --- a/src/library/browse/browsefeature.cpp +++ b/src/library/browse/browsefeature.cpp @@ -35,6 +35,7 @@ BrowseFeature::BrowseFeature( m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_browseModel(this, pLibrary->trackCollectionManager(), pRecordingManager), m_proxyModel(&m_browseModel), + m_pSidebarModel(new FolderTreeModel(this)), m_pLastRightClickedItem(nullptr), m_icon(":/images/library/ic_library_computer.svg") { connect(this, @@ -131,7 +132,7 @@ BrowseFeature::BrowseFeature( } // initialize the model - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); } BrowseFeature::~BrowseFeature() { @@ -150,12 +151,12 @@ void BrowseFeature::slotAddQuickLink() { QString spath = vpath.toString(); QString name = extractNameFromPath(spath); - QModelIndex parent = m_childModel.index(m_pQuickLinkItem->parentRow(), 0); + QModelIndex parent = m_pSidebarModel->index(m_pQuickLinkItem->parentRow(), 0); auto pNewChild = std::make_unique(name, vpath); QList rows; rows.append(pNewChild.get()); pNewChild.release(); - m_childModel.insertTreeItemRows(rows, m_pQuickLinkItem->childRows(), parent); + m_pSidebarModel->insertTreeItemRows(rows, m_pQuickLinkItem->childRows(), parent); m_quickLinkList.append(spath); saveQuickLinks(); @@ -206,8 +207,8 @@ void BrowseFeature::slotRemoveQuickLink() { return; } - QModelIndex parent = m_childModel.index(m_pQuickLinkItem->parentRow(), 0); - m_childModel.removeRow(index, parent); + QModelIndex parent = m_pSidebarModel->index(m_pQuickLinkItem->parentRow(), 0); + m_pSidebarModel->removeRow(index, parent); m_quickLinkList.removeAt(index); saveQuickLinks(); @@ -217,8 +218,8 @@ QIcon BrowseFeature::getIcon() { return m_icon; } -TreeItemModel* BrowseFeature::getChildModel() { - return &m_childModel; +TreeItemModel* BrowseFeature::sidebarModel() const { + return m_pSidebarModel; } void BrowseFeature::bindLibraryWidget(WLibrary* libraryWidget, @@ -392,7 +393,7 @@ void BrowseFeature::onLazyChildExpandation(const QModelIndex& index) { } // Before we populate the subtree, we need to delete old subtrees - m_childModel.removeRows(0, item->childRows(), index); + m_pSidebarModel->removeRows(0, item->childRows(), index); // List of subfolders or drive letters QList folders; @@ -428,7 +429,7 @@ void BrowseFeature::onLazyChildExpandation(const QModelIndex& index) { // On Ubuntu 10.04, otherwise, this will draw an icon although the folder // has no subfolders if (!folders.isEmpty()) { - m_childModel.insertTreeItemRows(folders, 0, index); + m_pSidebarModel->insertTreeItemRows(folders, 0, index); } } diff --git a/src/library/browse/browsefeature.h b/src/library/browse/browsefeature.h index a90fdded19a..97b10a6ef6c 100644 --- a/src/library/browse/browsefeature.h +++ b/src/library/browse/browsefeature.h @@ -37,7 +37,7 @@ class BrowseFeature : public LibraryFeature { KeyboardEventFilter* keyboard); void bindSidebarWidget(WLibrarySidebar* pSidebarWidget); - TreeItemModel* getChildModel(); + TreeItemModel* sidebarModel() const; public slots: void slotAddQuickLink(); @@ -66,7 +66,7 @@ class BrowseFeature : public LibraryFeature { BrowseTableModel m_browseModel; ProxyTrackModel m_proxyModel; - FolderTreeModel m_childModel; + FolderTreeModel* m_pSidebarModel; QAction* m_pAddQuickLinkAction; QAction* m_pRemoveQuickLinkAction; QAction* m_pAddtoLibraryAction; diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index 50ecab94783..0f924c0dcd9 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -64,6 +64,7 @@ QString localhost_token() { ITunesFeature::ITunesFeature(Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), + m_pSidebarModel(new TreeItemModel(this)), m_cancelImport(false), m_icon(":/images/library/ic_library_itunes.svg") { QString tableName = "itunes_library"; @@ -237,8 +238,8 @@ void ITunesFeature::activateChild(const QModelIndex& index) { emit enableCoverArtDisplay(false); } -TreeItemModel* ITunesFeature::getChildModel() { - return &m_childModel; +TreeItemModel* ITunesFeature::sidebarModel() const { + return m_pSidebarModel; } void ITunesFeature::onRightClick(const QPoint& globalPos) { @@ -820,7 +821,7 @@ void ITunesFeature::clearTable(const QString& table_name) { void ITunesFeature::onTrackCollectionLoaded() { std::unique_ptr root(m_future.result()); if (root) { - m_childModel.setRootItem(std::move(root)); + m_pSidebarModel->setRootItem(std::move(root)); // Tell the rhythmbox track source that it should re-build its index. m_trackSource->buildIndex(); diff --git a/src/library/itunes/itunesfeature.h b/src/library/itunes/itunesfeature.h index a3cd26b1ffe..c0828d8f134 100644 --- a/src/library/itunes/itunesfeature.h +++ b/src/library/itunes/itunesfeature.h @@ -27,7 +27,7 @@ class ITunesFeature : public BaseExternalLibraryFeature { QIcon getIcon() override; void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -52,7 +52,7 @@ class ITunesFeature : public BaseExternalLibraryFeature { BaseExternalTrackModel* m_pITunesTrackModel; BaseExternalPlaylistModel* m_pITunesPlaylistModel; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; QStringList m_playlists; // a new DB connection for the worker thread QSqlDatabase m_database; diff --git a/src/library/libraryfeature.h b/src/library/libraryfeature.h index 465b48c23f2..e28ed99c50d 100644 --- a/src/library/libraryfeature.h +++ b/src/library/libraryfeature.h @@ -62,7 +62,7 @@ class LibraryFeature : public QObject { virtual void bindLibraryWidget(WLibrary* /* libraryWidget */, KeyboardEventFilter* /* keyboard */) {} virtual void bindSidebarWidget(WLibrarySidebar* /* sidebar widget */) {} - virtual TreeItemModel* getChildModel() = 0; + virtual TreeItemModel* sidebarModel() const = 0; virtual bool hasTrackTable() { return false; diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp index 83f80252307..2957384128c 100644 --- a/src/library/mixxxlibraryfeature.cpp +++ b/src/library/mixxxlibraryfeature.cpp @@ -75,6 +75,7 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, m_icon(":/images/library/ic_library_tracks.svg"), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_pLibraryTableModel(nullptr), + m_pSidebarModel(new TreeItemModel(this)), m_pMissingView(nullptr), m_pHiddenView(nullptr) { QStringList columns = DEFAULT_COLUMNS; @@ -110,7 +111,7 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, pRootItem->appendChild(kMissingTitle); pRootItem->appendChild(kHiddenTitle); - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); #ifdef __ENGINEPRIME__ m_pExportLibraryAction = make_parented(tr("Export to Engine Prime"), this); @@ -148,8 +149,8 @@ QIcon MixxxLibraryFeature::getIcon() { return m_icon; } -TreeItemModel* MixxxLibraryFeature::getChildModel() { - return &m_childModel; +TreeItemModel* MixxxLibraryFeature::sidebarModel() const { + return m_pSidebarModel; } void MixxxLibraryFeature::refreshLibraryModels() { diff --git a/src/library/mixxxlibraryfeature.h b/src/library/mixxxlibraryfeature.h index c84d29c38c3..09595840a60 100644 --- a/src/library/mixxxlibraryfeature.h +++ b/src/library/mixxxlibraryfeature.h @@ -37,7 +37,7 @@ class MixxxLibraryFeature final : public LibraryFeature { QIcon getIcon() override; bool dropAccept(const QList& urls, QObject* pSource) override; bool dragMoveAccept(const QUrl& url) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; void bindLibraryWidget(WLibrary* pLibrary, KeyboardEventFilter* pKeyboard) override; #ifdef __ENGINEPRIME__ @@ -73,7 +73,7 @@ class MixxxLibraryFeature final : public LibraryFeature { QSharedPointer m_pBaseTrackCache; LibraryTableModel* m_pLibraryTableModel; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; DlgMissing* m_pMissingView; DlgHidden* m_pHiddenView; diff --git a/src/library/recording/recordingfeature.cpp b/src/library/recording/recordingfeature.cpp index 43655334291..3fb2497a710 100644 --- a/src/library/recording/recordingfeature.cpp +++ b/src/library/recording/recordingfeature.cpp @@ -16,11 +16,12 @@ const QString kViewName = QStringLiteral("Recording"); } // anonymous namespace RecordingFeature::RecordingFeature(Library* pLibrary, - UserSettingsPointer pConfig, - RecordingManager* pRecordingManager) + UserSettingsPointer pConfig, + RecordingManager* pRecordingManager) : LibraryFeature(pLibrary, pConfig), m_pRecordingManager(pRecordingManager), - m_icon(":/images/library/ic_library_recordings.svg") { + m_icon(":/images/library/ic_library_recordings.svg"), + m_pSidebarModel(new FolderTreeModel(this)) { } QVariant RecordingFeature::title() { @@ -31,8 +32,8 @@ QIcon RecordingFeature::getIcon() { return m_icon; } -TreeItemModel* RecordingFeature::getChildModel() { - return &m_childModel; +TreeItemModel* RecordingFeature::sidebarModel() const { + return m_pSidebarModel; } void RecordingFeature::bindLibraryWidget(WLibrary* pLibraryWidget, KeyboardEventFilter *keyboard) { diff --git a/src/library/recording/recordingfeature.h b/src/library/recording/recordingfeature.h index 61b26ad7821..7ef491a42aa 100644 --- a/src/library/recording/recordingfeature.h +++ b/src/library/recording/recordingfeature.h @@ -25,7 +25,7 @@ class RecordingFeature final : public LibraryFeature { void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -39,5 +39,5 @@ class RecordingFeature final : public LibraryFeature { RecordingManager* const m_pRecordingManager; const QIcon m_icon; - FolderTreeModel m_childModel; + FolderTreeModel* m_pSidebarModel; }; diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 0e7a0d01552..61c5efc687b 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1326,6 +1326,7 @@ RekordboxFeature::RekordboxFeature( Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), + m_pSidebarModel(new TreeItemModel(this)), m_icon(":/images/library/ic_library_rekordbox.svg") { QString tableName = kRekordboxLibraryTable; QString idColumn = LIBRARYTABLE_ID; @@ -1391,7 +1392,7 @@ RekordboxFeature::RekordboxFeature( this, &RekordboxFeature::onTracksFound); // initialize the model - m_childModel.setRootItem(TreeItem::newRoot(this)); + m_pSidebarModel->setRootItem(TreeItem::newRoot(this)); } RekordboxFeature::~RekordboxFeature() { @@ -1446,8 +1447,8 @@ bool RekordboxFeature::isSupported() { return true; } -TreeItemModel* RekordboxFeature::getChildModel() { - return &m_childModel; +TreeItemModel* RekordboxFeature::sidebarModel() const { + return m_pSidebarModel; } QString RekordboxFeature::formatRootViewHtml() const { @@ -1554,7 +1555,7 @@ void RekordboxFeature::activateChild(const QModelIndex& index) { void RekordboxFeature::onRekordboxDevicesFound() { QList foundDevices = m_devicesFuture.result(); - TreeItem* root = m_childModel.getRootItem(); + TreeItem* root = m_pSidebarModel->getRootItem(); QSqlDatabase database = m_pTrackCollection->database(); @@ -1575,7 +1576,7 @@ void RekordboxFeature::onRekordboxDevicesFound() { if (root->childRows() > 0) { // Devices have since been unmounted - m_childModel.removeRows(0, root->childRows()); + m_pSidebarModel->removeRows(0, root->childRows()); } } else { for (int deviceIndex = 0; deviceIndex < root->childRows(); deviceIndex++) { @@ -1595,7 +1596,7 @@ void RekordboxFeature::onRekordboxDevicesFound() { // Device has since been unmounted, cleanup DB clearDeviceTables(database, child); - m_childModel.removeRows(deviceIndex, 1); + m_pSidebarModel->removeRows(deviceIndex, 1); } } @@ -1620,7 +1621,7 @@ void RekordboxFeature::onRekordboxDevicesFound() { } if (!childrenToAdd.empty()) { - m_childModel.insertTreeItemRows(childrenToAdd, 0); + m_pSidebarModel->insertTreeItemRows(childrenToAdd, 0); } } @@ -1631,7 +1632,7 @@ void RekordboxFeature::onRekordboxDevicesFound() { void RekordboxFeature::onTracksFound() { qDebug() << "onTracksFound"; - m_childModel.triggerRepaint(); + m_pSidebarModel->triggerRepaint(); QString devicePlaylist = m_tracksFuture.result(); diff --git a/src/library/rekordbox/rekordboxfeature.h b/src/library/rekordbox/rekordboxfeature.h index c1388cef3f1..af33d88874d 100644 --- a/src/library/rekordbox/rekordboxfeature.h +++ b/src/library/rekordbox/rekordboxfeature.h @@ -64,7 +64,7 @@ class RekordboxFeature : public BaseExternalLibraryFeature { void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -80,7 +80,7 @@ class RekordboxFeature : public BaseExternalLibraryFeature { QString formatRootViewHtml() const; BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; RekordboxPlaylistModel* m_pRekordboxPlaylistModel; QFutureWatcher> m_devicesFutureWatcher; diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp index 5607d112585..aa66bf79b51 100644 --- a/src/library/rhythmbox/rhythmboxfeature.cpp +++ b/src/library/rhythmbox/rhythmboxfeature.cpp @@ -16,6 +16,7 @@ RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), + m_pSidebarModel(new TreeItemModel(this)), m_cancelImport(false), m_icon(":/images/library/ic_library_rhythmbox.svg") { QString tableName = "rhythmbox_library"; @@ -112,8 +113,8 @@ QIcon RhythmboxFeature::getIcon() { return m_icon; } -TreeItemModel* RhythmboxFeature::getChildModel() { - return &m_childModel; +TreeItemModel* RhythmboxFeature::sidebarModel() const { + return m_pSidebarModel; } void RhythmboxFeature::activate() { @@ -432,7 +433,7 @@ void RhythmboxFeature::clearTable(const QString& table_name) { void RhythmboxFeature::onTrackCollectionLoaded() { std::unique_ptr root(m_track_future.result()); if (root) { - m_childModel.setRootItem(std::move(root)); + m_pSidebarModel->setRootItem(std::move(root)); // Tell the rhythmbox track source that it should re-build its index. m_trackSource->buildIndex(); diff --git a/src/library/rhythmbox/rhythmboxfeature.h b/src/library/rhythmbox/rhythmboxfeature.h index fd2ef67f76c..dc74bf50b15 100644 --- a/src/library/rhythmbox/rhythmboxfeature.h +++ b/src/library/rhythmbox/rhythmboxfeature.h @@ -24,7 +24,7 @@ class RhythmboxFeature : public BaseExternalLibraryFeature { QVariant title(); QIcon getIcon(); - TreeItemModel* getChildModel(); + TreeItemModel* sidebarModel() const; // processes the music collection TreeItem* importMusicCollection(); // processes the playlist entries @@ -54,7 +54,7 @@ class RhythmboxFeature : public BaseExternalLibraryFeature { QFutureWatcher m_track_watcher; QFuture m_track_future; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; bool m_cancelImport; QSharedPointer m_trackSource; diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index b9fe1182e74..919063807e4 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -847,6 +847,7 @@ SeratoFeature::SeratoFeature( Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), + m_pSidebarModel(new TreeItemModel(this)), m_icon(":/images/library/ic_library_serato.svg") { QStringList columns; columns << LIBRARYTABLE_ID @@ -912,7 +913,7 @@ SeratoFeature::SeratoFeature( &SeratoFeature::onTracksFound); // initialize the model - m_childModel.setRootItem(TreeItem::newRoot(this)); + m_pSidebarModel->setRootItem(TreeItem::newRoot(this)); } SeratoFeature::~SeratoFeature() { @@ -967,8 +968,8 @@ bool SeratoFeature::isSupported() { return true; } -TreeItemModel* SeratoFeature::getChildModel() { - return &m_childModel; +TreeItemModel* SeratoFeature::sidebarModel() const { + return m_pSidebarModel; } QString SeratoFeature::formatRootViewHtml() const { @@ -1059,7 +1060,7 @@ void SeratoFeature::activateChild(const QModelIndex& index) { void SeratoFeature::onSeratoDatabasesFound() { QList foundDatabases = m_databasesFuture.result(); - TreeItem* root = m_childModel.getRootItem(); + TreeItem* root = m_pSidebarModel->getRootItem(); QSqlDatabase database = m_pTrackCollection->database(); @@ -1068,7 +1069,7 @@ void SeratoFeature::onSeratoDatabasesFound() { if (root->childRows() > 0) { // Devices have since been unmounted - m_childModel.removeRows(0, root->childRows()); + m_pSidebarModel->removeRows(0, root->childRows()); } } else { for (int databaseIndex = 0; databaseIndex < root->childRows(); databaseIndex++) { @@ -1087,7 +1088,7 @@ void SeratoFeature::onSeratoDatabasesFound() { if (removeChild) { // Device has since been unmounted, cleanup DB - m_childModel.removeRows(databaseIndex, 1); + m_pSidebarModel->removeRows(databaseIndex, 1); } } @@ -1112,7 +1113,7 @@ void SeratoFeature::onSeratoDatabasesFound() { } if (!childrenToAdd.empty()) { - m_childModel.insertTreeItemRows(childrenToAdd, 0); + m_pSidebarModel->insertTreeItemRows(childrenToAdd, 0); } } @@ -1123,7 +1124,7 @@ void SeratoFeature::onSeratoDatabasesFound() { void SeratoFeature::onTracksFound() { qDebug() << "onTracksFound"; - m_childModel.triggerRepaint(); + m_pSidebarModel->triggerRepaint(); QString databasePlaylist = m_tracksFuture.result(); diff --git a/src/library/serato/seratofeature.h b/src/library/serato/seratofeature.h index 515add942e8..0bdac04cd2e 100644 --- a/src/library/serato/seratofeature.h +++ b/src/library/serato/seratofeature.h @@ -34,7 +34,7 @@ class SeratoFeature : public BaseExternalLibraryFeature { void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -50,7 +50,7 @@ class SeratoFeature : public BaseExternalLibraryFeature { QString formatRootViewHtml() const; BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; SeratoPlaylistModel* m_pSeratoPlaylistModel; QFutureWatcher> m_databasesFutureWatcher; diff --git a/src/library/sidebarmodel.cpp b/src/library/sidebarmodel.cpp index eabd0f09213..50161fdcfee 100644 --- a/src/library/sidebarmodel.cpp +++ b/src/library/sidebarmodel.cpp @@ -47,7 +47,7 @@ void SidebarModel::addLibraryFeature(LibraryFeature* pFeature) { this, &SidebarModel::slotFeatureSelect); - QAbstractItemModel* model = pFeature->getChildModel(); + QAbstractItemModel* model = pFeature->sidebarModel(); connect(model, &QAbstractItemModel::modelAboutToBeReset, @@ -110,7 +110,7 @@ QModelIndex SidebarModel::index(int row, int column, * we return its associated childmodel */ if (parent.internalPointer() == this) { - const QAbstractItemModel* childModel = m_sFeatures[parent.row()]->getChildModel(); + const QAbstractItemModel* childModel = m_sFeatures[parent.row()]->sidebarModel(); QModelIndex childIndex = childModel->index(row, column); TreeItem* pTreeItem = static_cast(childIndex.internalPointer()); if (pTreeItem && childIndex.isValid()) { @@ -181,7 +181,7 @@ int SidebarModel::rowCount(const QModelIndex& parent) const { //qDebug() << "SidebarModel::rowCount parent=" << parent.getData(); if (parent.isValid()) { if (parent.internalPointer() == this) { - return m_sFeatures[parent.row()]->getChildModel()->rowCount(); + return m_sFeatures[parent.row()]->sidebarModel()->rowCount(); } else { // We support tree models deeper than 1 level TreeItem* pTreeItem = static_cast(parent.internalPointer()); @@ -209,7 +209,7 @@ bool SidebarModel::hasChildren(const QModelIndex& parent) const { TreeItem* pTreeItem = static_cast(parent.internalPointer()); if (pTreeItem) { LibraryFeature* pFeature = pTreeItem->feature(); - return pFeature->getChildModel()->hasChildren(parent); + return pFeature->sidebarModel()->hasChildren(parent); } } } @@ -409,7 +409,7 @@ QModelIndex SidebarModel::translateIndex( //Comment from Tobias Rafreider --> Dead Code???? for (int i = 0; i < m_sFeatures.size(); ++i) { - if (m_sFeatures[i]->getChildModel() == pModel) { + if (m_sFeatures[i]->sidebarModel() == pModel) { translatedIndex = createIndex(i, 0, this); } } diff --git a/src/library/trackset/baseplaylistfeature.cpp b/src/library/trackset/baseplaylistfeature.cpp index 47360198064..18d215db6c7 100644 --- a/src/library/trackset/baseplaylistfeature.cpp +++ b/src/library/trackset/baseplaylistfeature.cpp @@ -369,7 +369,7 @@ int BasePlaylistFeature::getSiblingPlaylistIdOf(QModelIndex& start) { for (int i = start.row() + 1; i >= (start.row() - 1); i -= 2) { QModelIndex nextIndex = start.sibling(i, start.column()); if (nextIndex.isValid()) { - TreeItem* pTreeItem = m_childModel.getItem(nextIndex); + TreeItem* pTreeItem = m_pSidebarModel->getItem(nextIndex); DEBUG_ASSERT(pTreeItem != nullptr); if (!pTreeItem->hasChildren()) { return playlistIdFromIndex(nextIndex); @@ -656,8 +656,8 @@ void BasePlaylistFeature::slotAnalyzePlaylist() { } } -TreeItemModel* BasePlaylistFeature::getChildModel() { - return &m_childModel; +TreeItemModel* BasePlaylistFeature::sidebarModel() const { + return m_pSidebarModel; } void BasePlaylistFeature::bindLibraryWidget(WLibrary* libraryWidget, @@ -692,9 +692,9 @@ void BasePlaylistFeature::updateChildModel(int playlistId) { QVariant variantId = QVariant(playlistId); - for (int row = 0; row < m_childModel.rowCount(); ++row) { - QModelIndex index = m_childModel.index(row, 0); - TreeItem* pTreeItem = m_childModel.getItem(index); + for (int row = 0; row < m_pSidebarModel->rowCount(); ++row) { + QModelIndex index = m_pSidebarModel->index(row, 0); + TreeItem* pTreeItem = m_pSidebarModel->getItem(index); DEBUG_ASSERT(pTreeItem != nullptr); if (!pTreeItem->hasChildren() && // leaf node pTreeItem->getData() == variantId) { @@ -708,13 +708,13 @@ void BasePlaylistFeature::updateChildModel(int playlistId) { * Clears the child model dynamically, but the invisible root item remains */ void BasePlaylistFeature::clearChildModel() { - m_childModel.removeRows(0, m_childModel.rowCount()); + m_pSidebarModel->removeRows(0, m_pSidebarModel->rowCount()); } QModelIndex BasePlaylistFeature::indexFromPlaylistId(int playlistId) { QVariant variantId = QVariant(playlistId); - QModelIndexList results = m_childModel.match( - m_childModel.getRootIndex(), + QModelIndexList results = m_pSidebarModel->match( + m_pSidebarModel->getRootIndex(), TreeItemModel::kDataRole, variantId, 1, @@ -733,14 +733,14 @@ void BasePlaylistFeature::slotTrackSelected(TrackPointer pTrack) { } m_playlistDao.getPlaylistsTrackIsIn(trackId, &m_playlistIdsOfSelectedTrack); - for (int row = 0; row < m_childModel.rowCount(); ++row) { - QModelIndex index = m_childModel.index(row, 0); - TreeItem* pTreeItem = m_childModel.getItem(index); + for (int row = 0; row < m_pSidebarModel->rowCount(); ++row) { + QModelIndex index = m_pSidebarModel->index(row, 0); + TreeItem* pTreeItem = m_pSidebarModel->getItem(index); DEBUG_ASSERT(pTreeItem != nullptr); markTreeItem(pTreeItem); } - m_childModel.triggerRepaint(); + m_pSidebarModel->triggerRepaint(); } void BasePlaylistFeature::markTreeItem(TreeItem* pTreeItem) { diff --git a/src/library/trackset/baseplaylistfeature.h b/src/library/trackset/baseplaylistfeature.h index 60b18cb9a33..f9e4c4aab0a 100644 --- a/src/library/trackset/baseplaylistfeature.h +++ b/src/library/trackset/baseplaylistfeature.h @@ -33,7 +33,7 @@ class BasePlaylistFeature : public BaseTrackSetFeature { const QString& rootViewName); ~BasePlaylistFeature() override = default; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; diff --git a/src/library/trackset/basetracksetfeature.cpp b/src/library/trackset/basetracksetfeature.cpp index 35d7d407351..cc0bc5b67c1 100644 --- a/src/library/trackset/basetracksetfeature.cpp +++ b/src/library/trackset/basetracksetfeature.cpp @@ -7,7 +7,8 @@ BaseTrackSetFeature::BaseTrackSetFeature( UserSettingsPointer pConfig, const QString& rootViewName) : LibraryFeature(pLibrary, pConfig), - m_rootViewName(rootViewName) { + m_rootViewName(rootViewName), + m_pSidebarModel(new TreeItemModel(this)) { } void BaseTrackSetFeature::activate() { diff --git a/src/library/trackset/basetracksetfeature.h b/src/library/trackset/basetracksetfeature.h index 37a4e8b77f5..dd1ced11e63 100644 --- a/src/library/trackset/basetracksetfeature.h +++ b/src/library/trackset/basetracksetfeature.h @@ -19,5 +19,5 @@ class BaseTrackSetFeature : public LibraryFeature { protected: const QString m_rootViewName; - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; }; diff --git a/src/library/trackset/crate/cratefeature.cpp b/src/library/trackset/crate/cratefeature.cpp index e2669811de3..6bbc1d53dbd 100644 --- a/src/library/trackset/crate/cratefeature.cpp +++ b/src/library/trackset/crate/cratefeature.cpp @@ -49,7 +49,7 @@ CrateFeature::CrateFeature(Library* pLibrary, initActions(); // construct child model - m_childModel.setRootItem(TreeItem::newRoot(this)); + m_pSidebarModel->setRootItem(TreeItem::newRoot(this)); rebuildChildModel(); connectLibrary(pLibrary); @@ -279,8 +279,8 @@ void CrateFeature::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) { m_pSidebarWidget = pSidebarWidget; } -TreeItemModel* CrateFeature::getChildModel() { - return &m_childModel; +TreeItemModel* CrateFeature::sidebarModel() const { + return m_pSidebarModel; } void CrateFeature::activateChild(const QModelIndex& index) { @@ -489,11 +489,11 @@ void CrateFeature::slotAutoDjTrackSourceChanged() { QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { qDebug() << "CrateFeature::rebuildChildModel()" << selectedCrateId; - TreeItem* pRootItem = m_childModel.getRootItem(); + TreeItem* pRootItem = m_pSidebarModel->getRootItem(); VERIFY_OR_DEBUG_ASSERT(pRootItem != nullptr) { return QModelIndex(); } - m_childModel.removeRows(0, pRootItem->childRows()); + m_pSidebarModel->removeRows(0, pRootItem->childRows()); QList modelRows; modelRows.reserve(m_pTrackCollection->crates().countCrates()); @@ -513,13 +513,13 @@ QModelIndex CrateFeature::rebuildChildModel(CrateId selectedCrateId) { } // Append all the newly created TreeItems in a dynamic way to the childmodel - m_childModel.insertTreeItemRows(modelRows, 0); + m_pSidebarModel->insertTreeItemRows(modelRows, 0); // Update rendering of crates depending on the currently selected track slotTrackSelected(m_pSelectedTrack); if (selectedRow >= 0) { - return m_childModel.index(selectedRow, 0); + return m_pSidebarModel->index(selectedRow, 0); } else { return QModelIndex(); } @@ -538,8 +538,8 @@ void CrateFeature::updateChildModel(const QSet& updatedCrateIds) { continue; } updateTreeItemForCrateSummary( - m_childModel.getItem(index), crateSummary); - m_childModel.triggerRepaint(index); + m_pSidebarModel->getItem(index), crateSummary); + m_pSidebarModel->triggerRepaint(index); } if (m_pSelectedTrack) { // Crates containing the currently selected track might @@ -563,9 +563,9 @@ QModelIndex CrateFeature::indexFromCrateId(CrateId crateId) const { VERIFY_OR_DEBUG_ASSERT(crateId.isValid()) { return QModelIndex(); } - for (int row = 0; row < m_childModel.rowCount(); ++row) { - QModelIndex index = m_childModel.index(row, 0); - TreeItem* pTreeItem = m_childModel.getItem(index); + for (int row = 0; row < m_pSidebarModel->rowCount(); ++row) { + QModelIndex index = m_pSidebarModel->index(row, 0); + TreeItem* pTreeItem = m_pSidebarModel->getItem(index); DEBUG_ASSERT(pTreeItem != nullptr); if (!pTreeItem->hasChildren() && // leaf node (CrateId(pTreeItem->getData()) == crateId)) { @@ -805,7 +805,7 @@ void CrateFeature::htmlLinkClicked(const QUrl& link) { void CrateFeature::slotTrackSelected(TrackPointer pTrack) { m_pSelectedTrack = std::move(pTrack); - TreeItem* pRootItem = m_childModel.getRootItem(); + TreeItem* pRootItem = m_pSidebarModel->getRootItem(); VERIFY_OR_DEBUG_ASSERT(pRootItem != nullptr) { return; } @@ -834,7 +834,7 @@ void CrateFeature::slotTrackSelected(TrackPointer pTrack) { pTreeItem->setBold(crateContainsSelectedTrack); } - m_childModel.triggerRepaint(); + m_pSidebarModel->triggerRepaint(); } void CrateFeature::slotResetSelectedTrack() { diff --git a/src/library/trackset/crate/cratefeature.h b/src/library/trackset/crate/cratefeature.h index 2b1d77c5047..0ed793692d8 100644 --- a/src/library/trackset/crate/cratefeature.h +++ b/src/library/trackset/crate/cratefeature.h @@ -41,7 +41,7 @@ class CrateFeature : public BaseTrackSetFeature { KeyboardEventFilter* keyboard) override; void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activateChild(const QModelIndex& index) override; diff --git a/src/library/trackset/playlistfeature.cpp b/src/library/trackset/playlistfeature.cpp index 3d9a42df80a..5dcc4aa0a8a 100644 --- a/src/library/trackset/playlistfeature.cpp +++ b/src/library/trackset/playlistfeature.cpp @@ -46,7 +46,7 @@ PlaylistFeature::PlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig) m_icon(QStringLiteral(":/images/library/ic_library_playlist.svg")) { // construct child model std::unique_ptr pRootItem = TreeItem::newRoot(this); - m_childModel.setRootItem(std::move(pRootItem)); + m_pSidebarModel->setRootItem(std::move(pRootItem)); constructChildModel(kInvalidPlaylistId); } @@ -261,11 +261,11 @@ QModelIndex PlaylistFeature::constructChildModel(int selectedId) { } // Append all the newly created TreeItems in a dynamic way to the childmodel - m_childModel.insertTreeItemRows(data_list, 0); + m_pSidebarModel->insertTreeItemRows(data_list, 0); if (selectedRow == -1) { return QModelIndex(); } - return m_childModel.index(selectedRow, 0); + return m_pSidebarModel->index(selectedRow, 0); } void PlaylistFeature::decorateChild(TreeItem* item, int playlistId) { diff --git a/src/library/trackset/setlogfeature.cpp b/src/library/trackset/setlogfeature.cpp index bc5bdd0f60c..7e1b0cb968c 100644 --- a/src/library/trackset/setlogfeature.cpp +++ b/src/library/trackset/setlogfeature.cpp @@ -46,7 +46,7 @@ SetlogFeature::SetlogFeature( transaction.commit(); //construct child model - m_childModel.setRootItem(TreeItem::newRoot(this)); + m_pSidebarModel->setRootItem(TreeItem::newRoot(this)); constructChildModel(kInvalidPlaylistId); m_pJoinWithPreviousAction = new QAction(tr("Join with previous (below)"), this); @@ -220,7 +220,7 @@ QModelIndex SetlogFeature::constructChildModel(int selectedId) { } // Append all the newly created TreeItems in a dynamic way to the childmodel - m_childModel.insertTreeItemRows(itemList, 0); + m_pSidebarModel->insertTreeItemRows(itemList, 0); if (selectedId) { return indexFromPlaylistId(selectedId); diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 94760a3b3d2..7c1760126a6 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -65,6 +65,7 @@ bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) { TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), + m_pSidebarModel(new TreeItemModel(this)), m_cancelImport(false), m_icon(":/images/library/ic_library_traktor.svg") { QString tableName = "traktor_library"; @@ -151,8 +152,8 @@ bool TraktorFeature::isSupported() { return (QFile::exists(getTraktorMusicDatabase())); } -TreeItemModel* TraktorFeature::getChildModel() { - return &m_childModel; +TreeItemModel* TraktorFeature::sidebarModel() const { + return m_pSidebarModel; } void TraktorFeature::refreshLibraryModels() { @@ -619,7 +620,7 @@ QString TraktorFeature::getTraktorMusicDatabase() { void TraktorFeature::onTrackCollectionLoaded() { std::unique_ptr root(m_future.result()); if (root) { - m_childModel.setRootItem(std::move(root)); + m_pSidebarModel->setRootItem(std::move(root)); // Tell the traktor track source that it should re-build its index. m_trackSource->buildIndex(); diff --git a/src/library/traktor/traktorfeature.h b/src/library/traktor/traktorfeature.h index b685eb11937..e2e649f2bd9 100644 --- a/src/library/traktor/traktorfeature.h +++ b/src/library/traktor/traktorfeature.h @@ -38,7 +38,7 @@ class TraktorFeature : public BaseExternalLibraryFeature { QIcon getIcon() override; static bool isSupported(); - TreeItemModel* getChildModel() override; + TreeItemModel* sidebarModel() const override; public slots: void activate() override; @@ -61,7 +61,7 @@ class TraktorFeature : public BaseExternalLibraryFeature { void clearTable(const QString& table_name); static QString getTraktorMusicDatabase(); // private fields - TreeItemModel m_childModel; + TreeItemModel* m_pSidebarModel; // A separate db connection for the worker parsing thread QSqlDatabase m_database; TraktorTrackModel* m_pTraktorTableModel; From 7ff005a510cbc410b00cce41b8ae581137089876 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 22 Jun 2021 23:51:43 +0200 Subject: [PATCH 006/194] CHANGELOG: Fix order in 2.3 changelog "Other" section --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2da1aed2e6f..e426a941d51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -116,10 +116,10 @@ * Add macOS codesigning and notarization to fix startup warnings [#3281](https://github.com/mixxxdj/mixxx/pull/3281) * Don't trash user configuration if an error occurs when writing [#3192](https://github.com/mixxxdj/mixxx/pull/3192) * Enable CUE sheet recording by default [#3374](https://github.com/mixxxdj/mixxx/pull/3374) -* And countless other small fixes and improvements (too many to list them all!) * Fix crash when double clicking GLSL waveforms with right mouse button [#3904](https://github.com/mixxxdj/mixxx/pull/3904) * Derive Mixxx version from `git describe` [#3824](https://github.com/mixxxdj/mixxx/pull/3824) [#3841](https://github.com/mixxxdj/mixxx/pull/3841) [#3848](https://github.com/mixxxdj/mixxx/pull/3848) * Improve tapping the bpm of a deck [#3790](https://github.com/mixxxdj/mixxx/pull/3790) [lp:1882776](https://bugs.launchpad.net/mixxx/+bug/1882776) +* And countless other small fixes and improvements (too many to list them all!) ## [2.2.4](https://launchpad.net/mixxx/+milestone/2.2.4) (2020-06-27) From 0322ac6a0f3d1b6c6efc92522ebe604f1cddde6a Mon Sep 17 00:00:00 2001 From: ehmic <1mail4me@web.de> Date: Wed, 23 Jun 2021 11:08:10 +0200 Subject: [PATCH 007/194] coding style fix --- src/library/dlgtagfetcher.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/library/dlgtagfetcher.cpp b/src/library/dlgtagfetcher.cpp index c7b593b9a40..c18e62c5794 100644 --- a/src/library/dlgtagfetcher.cpp +++ b/src/library/dlgtagfetcher.cpp @@ -41,9 +41,7 @@ QStringList trackReleaseColumnValues( << trackRelease.albumTitle << trackRelease.date << trackNumberAndTotal - << trackRelease.albumArtist - - ; + << trackRelease.albumArtist; return columnValues; } From ee0cc34dc928dbfe9b0ce0363fa785ea6326cd0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 23 Jun 2021 22:34:18 +0200 Subject: [PATCH 008/194] Pull latest translations from https://www.transifex.com/mixxx-dj-software/mixxxdj/mixxx2-4/. Compile QM files out of TS files that are used by the localized app --- res/translations/mixxx_en_GB.qm | Bin 315309 -> 315303 bytes res/translations/mixxx_en_GB.ts | 6 +- res/translations/mixxx_nl_BE.qm | Bin 361071 -> 379253 bytes res/translations/mixxx_nl_BE.ts | 156 ++++++++++++++++---------------- 4 files changed, 83 insertions(+), 79 deletions(-) diff --git a/res/translations/mixxx_en_GB.qm b/res/translations/mixxx_en_GB.qm index ad447a112bfae3ad2609fa09eb9dd2bb2bda4731..33d01db03a0a7ca20b65b6abf77dfdc7e4ff1e47 100644 GIT binary patch delta 14585 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 G>hph9)3%WS diff --git a/res/translations/mixxx_en_GB.ts b/res/translations/mixxx_en_GB.ts index 74a7206dc92..b1a3390e5c1 100644 --- a/res/translations/mixxx_en_GB.ts +++ b/res/translations/mixxx_en_GB.ts @@ -6353,7 +6353,7 @@ and allows you to pitch adjust them for harmonic mixing. Album - Album: + Album @@ -7368,13 +7368,13 @@ Select from different types of displays for the waveform, which differ primarily Artist - Artist: + Artist Album - Album: + Album diff --git a/res/translations/mixxx_nl_BE.qm b/res/translations/mixxx_nl_BE.qm index d44359bc6d2b76c35529920612434f336ecddf68..5e56bab96a6ba3753e3693bd6f8bb81f6f552a2d 100644 GIT binary patch delta 32860 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 delta 20149 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

G)-EtJqM=oTw0J3LVQ-Hv@i|X*Dt1!-~J^n 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 ch05XootIjK$6S<>l4@R-PD Donate - + Donaties @@ -3414,7 +3414,7 @@ Date: - + Datum: @@ -8224,7 +8224,7 @@ Wil je het echt overschrijven? One or more MixxxControls specified in the outputs section of the loaded mapping were invalid. - + Een of meer MixxxControls die in de uitvoersectie van de geladen mapping zijn gespecificeerd, waren ongeldig. @@ -8241,7 +8241,7 @@ Wil je het echt overschrijven? * Make sure the MixxxControls in question actually exist. Visit the manual for a complete list: - + * Zorg ervoor dat de MixxxControls in kwestie echt bestaan. Ga naar de handleiding voor een volledige lijst: @@ -8890,7 +8890,7 @@ Om deze actie af te breken, drukt u op Annuleren in het bestandsdialoogvenster.< Upgrading old Mixxx settings - + Oude Mixxx-instellingen upgraden @@ -8899,7 +8899,11 @@ Om deze actie af te breken, drukt u op Annuleren in het bestandsdialoogvenster.< To allow Mixxx to use your old library and settings, click the Open button in the file selection dialog. Mixxx will then move your old settings into the sandbox. This only needs to be done once. If you do not want to grant Mixxx access, click Cancel on the file picker. Mixxx will create a new music library and use default settings. - + Als gevolg van macOS sandboxing heeft Mixxx uw toestemming nodig om toegang te krijgen tot uw muziekbibliotheek en instellingen van Mixxx-versies vóór 2.3.0. Nadat u op OK hebt geklikt, ziet u een dialoogvenster voor bestandsselectie. + +Als u Mixxx toestemming wilt geven uw oude bibliotheek en instellingen te gebruiken, klikt u op de knop Openen in het dialoogvenster voor bestandsselectie. Mixxx zal dan uw oude instellingen naar de zandbak verplaatsen. Dit hoeft maar één keer te worden gedaan. + +Als u Mixxx geen toegang wilt verlenen, klikt u op Annuleren in de bestandkiezer. Mixxx maakt een nieuwe muziekbibliotheek en gebruikt standaardinstellingen. @@ -9957,7 +9961,7 @@ Volledig rechts: einde van de effectperiode Parameters of %1 - + Parameters van %1 @@ -9998,34 +10002,34 @@ Volledig rechts: einde van de effectperiode <html>Mixxx cannot record or stream in AAC or HE-AAC without the FDK-AAC encoder. In order to record or stream in AAC or AAC+, you need to download <b>libfdk-aac</b> and install it on your system. - + <html>Mixxx kan niet opnemen of streamen in AAC of HE-AAC zonder de FDK-AAC-encoder. Om op te nemen of te streamen in AAC of AAC+, moet u <b>libfdk-aac</b> downloaden en op uw systeem installeren. The installed AAC encoding library does not support HE-AAC, only plain AAC. Configure a different encoding format in the preferences. - + De geïnstalleerde AAC-coderingsbibliotheek ondersteunt HE-AAC niet, alleen gewone AAC. Configureer een ander coderingsformaat in de voorkeuren. MP3 encoding is not supported. Lame could not be initialized - + MP3-codering wordt niet ondersteund. Lame kan niet worden geïnitialiseerd OGG recording is not supported. OGG/Vorbis library could not be initialized. - + OGG-opname wordt niet ondersteund. OGG/Vorbis-bibliotheek kan niet worden geïnitialiseerd. encoder failure - + encoderfout Failed to apply the selected settings. - + Kan de geselecteerde instellingen niet toepassen. @@ -10163,12 +10167,12 @@ Volledig rechts: einde van de effectperiode Loops (only the first loop is currently usable in Mixxx) - + Loops (alleen de eerste loop is momenteel bruikbaar in Mixxx) Check for attached Rekordbox USB / SD devices (refresh) - + Controleer op aangesloten Rekordbox USB / SD-apparaten (vernieuwen) @@ -10178,7 +10182,7 @@ Volledig rechts: einde van de effectperiode Reads databases exported for Pioneer CDJ / XDJ players using the Rekordbox Export mode.<br/>Rekordbox can only export to USB or SD devices with a FAT or HFS file system.<br/>Mixxx can read a database from any device that contains the database folders (<tt>PIONEER</tt> and <tt>Contents</tt>).<br/>Not supported are Rekordbox databases that have been moved to an external device via<br/><i>Preferences > Advanced > Database management</i>.<br/><br/>The following data is read: - + Leest databases die zijn geëxporteerd voor Pioneer CDJ / XDJ-spelers met behulp van de <br/>Rekordbox Exportmodus.Rekordbox kan alleen exporteren naar USB- of SD-apparaten met een FAT- of HFS-bestandssysteem. <br/>Mixxx kan een database lezen van elk apparaat dat de databasemappen bevat (<tt>PIONEER</tt> en <tt>Inhoud</tt>). <br/>Niet ondersteund worden Rekordbox-databases die zijn verplaatst naar een extern apparaat via <br/><i>Voorkeuren > Geavanceerd > Databasebeheer</i>.<br/><br/>De volgende gegevens worden gelezen: @@ -10220,7 +10224,7 @@ Volledig rechts: einde van de effectperiode Mixxx Sampler Banks (*%1) - + Mixxx Sampler-banken (*%1) @@ -10423,17 +10427,17 @@ Volledig rechts: einde van de effectperiode Unknown stream encoding format! - + Onbekend stream coderingsformaat! Use a libshout version with %1 enabled - + Gebruik een libshout-versie met %1 ingeschakeld Error setting stream encoding format! - + Fout bij instellen van streamcoderingsformaat! @@ -10463,7 +10467,7 @@ Volledig rechts: einde van de effectperiode Error: Shoutcast only supports MP3 and AAC encoders - + Error: Shoutcast only supports MP3 and AAC encoders @@ -10644,7 +10648,7 @@ Volledig rechts: einde van de effectperiode Double-click - + Dubbelklik @@ -10654,7 +10658,7 @@ Volledig rechts: einde van de effectperiode Shift-key - + Shift-toets @@ -10735,12 +10739,12 @@ Volledig rechts: einde van de effectperiode Big Spinny/Cover Art - + Big Spinny/Cover Art Show a big version of the Spinny or track cover art if enabled. - + Toon een grote versie van de Spinny of track cover art indien ingeschakeld. @@ -10977,7 +10981,7 @@ Volledig rechts: einde van de effectperiode Show/hide Cover Art of the selected track in the library. - + Toon/verberg Cover Art van de geselecteerde track in de bibliotheek. @@ -10992,12 +10996,12 @@ Volledig rechts: einde van de effectperiode Show/hide the scrolling waveforms - + De scrollende waveforms tonen/verbergen Show/hide the beatgrid controls section - + Toon/verberg de beatgrid-besturingssectie @@ -11022,7 +11026,7 @@ Volledig rechts: einde van de effectperiode Hide all skin sections except the decks to have more screen space for the track library. - + Verberg alle skinsecties behalve de decks om meer schermruimte te hebben voor de trackbibliotheek. @@ -11037,12 +11041,12 @@ Volledig rechts: einde van de effectperiode Volume Meters - + Volumemeters Show/hide volume meters for channels and master output. - + Toon/verberg volumemeters voor kanalen en masteruitgang. @@ -11334,7 +11338,7 @@ Volledig rechts: einde van de effectperiode (while previewing) - + (tijdens het bekijken) @@ -11354,7 +11358,7 @@ Volledig rechts: einde van de effectperiode Is latching the playing state. - + Vergrendelt de afspeelstatus. @@ -11394,22 +11398,22 @@ Volledig rechts: einde van de effectperiode Tempo Range Display - + Tempobereikweergave Displays the current range of the tempo slider. - + Geeft het huidige bereik van de temposchuifregelaar weer. Delete selected hotcue. - + Verwijder de geselecteerde hotcue. Opens separate artwork viewer. - + Opent een aparte viewer voor artwork. @@ -11424,59 +11428,59 @@ Volledig rechts: einde van de effectperiode Auto: Automatically reduce music volume when microphone volume rises above threshold. - + Auto: automatisch het muziekvolume verlagen wanneer het microfoonvolume boven de drempel komt. Adjust the amount the music volume is reduced with the Strength knob. - + Pas de hoeveelheid aan waarmee het muziekvolume wordt verlaagd met de Sterkte-knop. Auto: Sets how much to reduce the music volume when the volume of active microphones rises above threshold. - + Auto: Stelt in hoeveel het muziekvolume moet worden verlaagd wanneer het volume van de actieve microfoons boven de drempel komt. Manual: Sets how much to reduce the music volume, when talkover is activated regardless of volume of microphone inputs. - + Handmatig: Stelt in hoeveel het muziekvolume moet worden verlaagd, wanneer talkover wordt geactiveerd, ongeacht het volume van de microfooningangen. Shift cues earlier - + Verschuif cues naar eerder Shift cues imported from Serato or Rekordbox if they are slightly off time. - + Verschuif cues geïmporteerd uit Serato of Rekordbox als ze een beetje uit de maat staan. Left click: shift 10 milliseconds earlier - + Linker klik: 10 milliseconden eerder verschuiven Right click: shift 1 millisecond earlier - + Rechts klikken: shift 1 milliseconde eerder Shift cues later - + Verschuif cues later Left click: shift 10 milliseconds later - + Linker klik: 10 milliseconden later verschuiven Right click: shift 1 millisecond later - + Rechts klikken: 1 milliseconde later verschuiven @@ -11486,7 +11490,7 @@ Volledig rechts: einde van de effectperiode Auto DJ is active - + Auto DJ is actief @@ -11651,7 +11655,7 @@ Volledig rechts: einde van de effectperiode Hint: Change the time format in Preferences -> Decks. - + Hint: Wijzig het tijdformaat in Voorkeuren -> Decks. @@ -12419,12 +12423,12 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte Opens the track properties editor - + Opent de track eigenschappen editor Opens the track context menu. - + Opent het track contextmenu. @@ -13676,20 +13680,20 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte Ready to play, analyzing... Text on waveform overview when file is playable but no waveform is visible - + Klaar om te spelen, analyseren... Loading track... Text on waveform overview when file is cached from source - + Track laden... Finalizing... Text on waveform overview during finalizing of waveform analysis - + Finaliseren... @@ -14029,12 +14033,12 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte Importing metadata of %n track(s) from file tags - + Metagegevens van %n track(s) uit bestandstags importerenMetagegevens van %n track(s) uit bestandstags importeren Marking metadata of %n track(s) to be exported into file tags - + Metagegevens van %n track(s) markeren om te exporteren naar bestandstagsMetagegevens van %n track(s) markeren om te exporteren naar bestandstags @@ -14082,92 +14086,92 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte Scaling BPM of %n track(s) - + BPM van %n track(s) schalenBPM van %n track(s) schalen Locking BPM of %n track(s) - + Vergrendelen BPM van %n track(s)Vergrendelen BPM van %n track(s) Unlocking BPM of %n track(s) - + Ontgrendelen BPM van %n track(s)Ontgrendelen BPM van %n track(s) Setting color of %n track(s) - + Instellen kleur van %n track(s)Instellen kleur van %n track(s) Resetting play count of %n track(s) - + Afspeeltelling van %n track(s) resettenAfspeeltelling van %n track(s) resetten Resetting beats of %n track(s) - + Beats van %n track(s) resettenBeats van %n track(s) resetten Clearing rating of %n track(s) - + Beoordeling van %n track(s) wissenBeoordeling van %n track(s) wissen Removing main cue from %n track(s) - + Hoofdcue verwijderen uit %n track(s)Hoofdcue verwijderen uit %n track(s) Removing outro cue from %n track(s) - + Outro cue verwijderen van %n track(s)Outro cue verwijderen van %n track(s) Removing intro cue from %n track(s) - + Intro cue verwijderen van %n track(s)Intro cue verwijderen van %n track(s) Removing loop cues from %n track(s) - + Loop cues verwijderen uit %n track(s)Loop cues verwijderen uit %n track(s) Removing hot cues from %n track(s) - + Hot cues verwijderen uit %n track(s)Hot cues verwijderen uit %n track(s) Resetting keys of %n track(s) - + Toetsen resetten van %n track(s)Toetsen resetten van %n track(s) Resetting replay gain of %n track(s) - + Terugspeelversterking van %n track(s) resettenTerugspeelversterking van %n track(s) resetten Resetting waveform of %n track(s) - + De waveform van %n track(s) resettenDe waveform van %n track(s) resetten Resetting all performance metadata of %n track(s) - + Alle performance metadata van %n track(s) resettenAlle performance metadata van %n track(s) resetten Setting cover art of %n track(s) - + Cover art van %n track(s) instellenCover art van %n track(s) instellen Reloading cover art of %n track(s) - + Herladen van cover art van %n track(s)Herladen van cover art van %n track(s) @@ -14228,7 +14232,7 @@ Gebruik deze optie om alleen het verwerkte (Wet) signaal met EQ en filtereffecte Abort - + Afbreken From 42984dd070ac81dbcb6e7cd9f132c5eb9f581a65 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Mon, 15 Mar 2021 15:51:51 -0400 Subject: [PATCH 009/194] Sync Lock: rename functions to make them clearer --- src/engine/controls/bpmcontrol.cpp | 2 +- src/engine/controls/bpmcontrol.h | 2 +- src/engine/sync/clock.h | 4 +- src/engine/sync/enginesync.cpp | 62 +++++++++++++++++------------- src/engine/sync/enginesync.h | 11 ++++-- src/engine/sync/internalclock.cpp | 18 ++++----- src/engine/sync/internalclock.h | 8 ++-- src/engine/sync/syncable.h | 16 ++++---- src/engine/sync/synccontrol.cpp | 24 ++++++------ src/engine/sync/synccontrol.h | 11 +++--- 10 files changed, 87 insertions(+), 71 deletions(-) diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index fac2e68e87d..d72f6ff7921 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -1104,7 +1104,7 @@ void BpmControl::setTargetBeatDistance(double beatDistance) { m_dSyncTargetBeatDistance.setValue(beatDistance); } -void BpmControl::setInstantaneousBpm(double instantaneousBpm) { +void BpmControl::updateInstantaneousBpm(double instantaneousBpm) { m_dSyncInstantaneousBpm = instantaneousBpm; } diff --git a/src/engine/controls/bpmcontrol.h b/src/engine/controls/bpmcontrol.h index f5cca122262..7e5e3446b26 100644 --- a/src/engine/controls/bpmcontrol.h +++ b/src/engine/controls/bpmcontrol.h @@ -47,7 +47,7 @@ class BpmControl : public EngineControl { } void setTargetBeatDistance(double beatDistance); - void setInstantaneousBpm(double instantaneousBpm); + void updateInstantaneousBpm(double instantaneousBpm); void resetSyncAdjustment(); double updateLocalBpm(); /// updateBeatDistance is adjusted to include the user offset so diff --git a/src/engine/sync/clock.h b/src/engine/sync/clock.h index 75d987fc2ae..9814bf1d441 100644 --- a/src/engine/sync/clock.h +++ b/src/engine/sync/clock.h @@ -5,8 +5,8 @@ class Clock { virtual ~Clock() = default; virtual double getBeatDistance() const = 0; - virtual void setMasterBeatDistance(double beatDistance) = 0; + virtual void updateMasterBeatDistance(double beatDistance) = 0; virtual double getBpm() const = 0; - virtual void setMasterBpm(double bpm) = 0; + virtual void updateMasterBpm(double bpm) = 0; }; diff --git a/src/engine/sync/enginesync.cpp b/src/engine/sync/enginesync.cpp index 474ff418e99..595be45439c 100644 --- a/src/engine/sync/enginesync.cpp +++ b/src/engine/sync/enginesync.cpp @@ -19,7 +19,7 @@ EngineSync::EngineSync(UserSettingsPointer pConfig) m_pInternalClock(new InternalClock(kInternalClockGroup, this)), m_pMasterSyncable(nullptr) { qRegisterMetaType("SyncMode"); - m_pInternalClock->setMasterBpm(124.0); + m_pInternalClock->updateMasterBpm(124.0); } EngineSync::~EngineSync() { @@ -90,14 +90,19 @@ void EngineSync::requestSyncMode(Syncable* pSyncable, SyncMode mode) { pParamsSyncable = findBpmMatchTarget(pSyncable); if (!pParamsSyncable) { // We weren't able to find anything to match to, so set ourselves as the - // target. That way we'll use our own params when we setMasterParams below. + // target. That way we'll use our own params when we updateMasterBpm below. pParamsSyncable = pSyncable; } } // Now that all of the decks have their assignments, reinit master params if needed. if (pParamsSyncable) { - setMasterParams(pParamsSyncable); - pSyncable->setInstantaneousBpm(pParamsSyncable->getBpm()); + if (kLogger.traceEnabled()) { + kLogger.trace() + << "EngineSync::requestSyncMode setting master params from " + << pParamsSyncable->getGroup(); + } + reinitMasterParams(pParamsSyncable); + pSyncable->updateInstantaneousBpm(pParamsSyncable->getBpm()); if (pParamsSyncable != pSyncable) { pSyncable->requestSync(); } @@ -194,6 +199,9 @@ void EngineSync::deactivateSync(Syncable* pSyncable) { } Syncable* EngineSync::pickMaster(Syncable* enabling_syncable) { + if (kLogger.traceEnabled()) { + kLogger.trace() << "EngineSync::pickMaster"; + } if (m_pMasterSyncable && m_pMasterSyncable->getSyncMode() == SYNC_MASTER_EXPLICIT && m_pMasterSyncable->getBaseBpm() != 0.0) { @@ -354,14 +362,14 @@ void EngineSync::notifyPlayingAudible(Syncable* pSyncable, bool playingAudible) if (newMaster != nullptr && newMaster != m_pMasterSyncable) { activateMaster(newMaster, SYNC_MASTER_SOFT); - setMasterParams(newMaster); + reinitMasterParams(newMaster); } else { Syncable* pOnlyPlayer = getUniquePlayingSyncedDeck(); if (pOnlyPlayer) { // Even if we didn't change master, if there is only one player (us), then we should - // reinit the beat distance. + // update the beat distance. pOnlyPlayer->notifyUniquePlaying(); - setMasterBeatDistance(pOnlyPlayer, pOnlyPlayer->getBeatDistance()); + updateMasterBeatDistance(pOnlyPlayer, pOnlyPlayer->getBeatDistance()); } } @@ -380,7 +388,7 @@ void EngineSync::notifyBaseBpmChanged(Syncable* pSyncable, double bpm) { } if (isSyncMaster(pSyncable)) { - setMasterBpm(pSyncable, bpm); + updateMasterBpm(pSyncable, bpm); } } @@ -389,7 +397,7 @@ void EngineSync::notifyRateChanged(Syncable* pSyncable, double bpm) { kLogger.trace() << "EngineSync::notifyRateChanged" << pSyncable->getGroup() << bpm; } - setMasterBpm(pSyncable, bpm); + updateMasterBpm(pSyncable, bpm); } void EngineSync::requestBpmUpdate(Syncable* pSyncable, double bpm) { @@ -408,10 +416,10 @@ void EngineSync::requestBpmUpdate(Syncable* pSyncable, double bpm) { if (mbaseBpm != 0.0) { // resync to current master - pSyncable->setMasterParams(beatDistance, mbaseBpm, mbpm); + pSyncable->reinitMasterParams(beatDistance, mbaseBpm, mbpm); } else { // There is no other master, adopt this bpm as master - pSyncable->setMasterParams(0.0, 0.0, bpm); + pSyncable->reinitMasterParams(0.0, 0.0, bpm); } } @@ -425,7 +433,7 @@ void EngineSync::notifyInstantaneousBpmChanged(Syncable* pSyncable, double bpm) // Do not update the master rate slider because instantaneous changes are // not user visible. - setMasterInstantaneousBpm(pSyncable, bpm); + updateMasterInstantaneousBpm(pSyncable, bpm); } void EngineSync::notifyBeatDistanceChanged(Syncable* pSyncable, double beatDistance) { @@ -437,7 +445,7 @@ void EngineSync::notifyBeatDistanceChanged(Syncable* pSyncable, double beatDista return; } - setMasterBeatDistance(pSyncable, beatDistance); + updateMasterBeatDistance(pSyncable, beatDistance); } Syncable* EngineSync::pickNonSyncSyncTarget(EngineChannel* pDontPick) const { @@ -564,52 +572,52 @@ double EngineSync::masterBaseBpm() const { return m_pInternalClock->getBaseBpm(); } -void EngineSync::setMasterBpm(Syncable* pSource, double bpm) { - //qDebug() << "EngineSync::setMasterBpm" << pSource << bpm; +void EngineSync::updateMasterBpm(Syncable* pSource, double bpm) { + //qDebug() << "EngineSync::updateMasterBpm" << pSource << bpm; if (pSource != m_pInternalClock) { - m_pInternalClock->setMasterBpm(bpm); + m_pInternalClock->updateMasterBpm(bpm); } foreach (Syncable* pSyncable, m_syncables) { if (pSyncable == pSource || !pSyncable->isSynchronized()) { continue; } - pSyncable->setMasterBpm(bpm); + pSyncable->updateMasterBpm(bpm); } } -void EngineSync::setMasterInstantaneousBpm(Syncable* pSource, double bpm) { +void EngineSync::updateMasterInstantaneousBpm(Syncable* pSource, double bpm) { if (pSource != m_pInternalClock) { - m_pInternalClock->setInstantaneousBpm(bpm); + m_pInternalClock->updateInstantaneousBpm(bpm); } foreach (Syncable* pSyncable, m_syncables) { if (pSyncable == pSource || !pSyncable->isSynchronized()) { continue; } - pSyncable->setInstantaneousBpm(bpm); + pSyncable->updateInstantaneousBpm(bpm); } } -void EngineSync::setMasterBeatDistance(Syncable* pSource, double beatDistance) { +void EngineSync::updateMasterBeatDistance(Syncable* pSource, double beatDistance) { if (kLogger.traceEnabled()) { kLogger.trace() << "EngineSync::setMasterBeatDistance" << (pSource ? pSource->getGroup() : "null") << beatDistance; } if (pSource != m_pInternalClock) { - m_pInternalClock->setMasterBeatDistance(beatDistance); + m_pInternalClock->updateMasterBeatDistance(beatDistance); } foreach (Syncable* pSyncable, m_syncables) { if (pSyncable == pSource || !pSyncable->isSynchronized()) { continue; } - pSyncable->setMasterBeatDistance(beatDistance); + pSyncable->updateMasterBeatDistance(beatDistance); } } -void EngineSync::setMasterParams(Syncable* pSource) { +void EngineSync::reinitMasterParams(Syncable* pSource) { // Important note! Because of the way sync works, the new master is usually not the same // as the Syncable setting the master parameters (here, pSource). Notify the proper Syncable // so it can prepare itself. (This is a hack to undo half/double math so that we initialize @@ -644,17 +652,17 @@ void EngineSync::setMasterParams(Syncable* pSource) { bpm = baseBpm; } if (kLogger.traceEnabled()) { - kLogger.trace() << "BaseSyncableListener::setMasterParams, source is" + kLogger.trace() << "BaseSyncableListener::reinitMasterParams, source is" << pSource->getGroup() << beatDistance << baseBpm << bpm; } if (pSource != m_pInternalClock) { - m_pInternalClock->setMasterParams(beatDistance, baseBpm, bpm); + m_pInternalClock->reinitMasterParams(beatDistance, baseBpm, bpm); } foreach (Syncable* pSyncable, m_syncables) { if (!pSyncable->isSynchronized()) { continue; } - pSyncable->setMasterParams(beatDistance, baseBpm, bpm); + pSyncable->reinitMasterParams(beatDistance, baseBpm, bpm); } } diff --git a/src/engine/sync/enginesync.h b/src/engine/sync/enginesync.h index 5ce7574b520..0e3118010b2 100644 --- a/src/engine/sync/enginesync.h +++ b/src/engine/sync/enginesync.h @@ -103,17 +103,20 @@ class EngineSync : public SyncableListener { double masterBaseBpm() const; /// Set the BPM on every sync-enabled Syncable except pSource. - void setMasterBpm(Syncable* pSource, double bpm); + void updateMasterBpm(Syncable* pSource, double bpm); /// Set the master instantaneous BPM on every sync-enabled Syncable except /// pSource. - void setMasterInstantaneousBpm(Syncable* pSource, double bpm); + void updateMasterInstantaneousBpm(Syncable* pSource, double bpm); /// Set the master beat distance on every sync-enabled Syncable except /// pSource. - void setMasterBeatDistance(Syncable* pSource, double beatDistance); + void updateMasterBeatDistance(Syncable* pSource, double beatDistance); - void setMasterParams(Syncable* pSource); + /// Initialize the master parameters using the provided syncable as the source. + /// This should only be called for "major" updates, like a new track or change in + /// master. Should not be called on every buffer callback. + void reinitMasterParams(Syncable* pSource); /// Iff there is a single playing syncable in sync mode, return it. /// This is used to initialize master params. diff --git a/src/engine/sync/internalclock.cpp b/src/engine/sync/internalclock.cpp index 734523d7e83..4beec9733fb 100644 --- a/src/engine/sync/internalclock.cpp +++ b/src/engine/sync/internalclock.cpp @@ -103,7 +103,7 @@ double InternalClock::getBeatDistance() const { return m_dClockPosition / m_dBeatLength; } -void InternalClock::setMasterBeatDistance(double beatDistance) { +void InternalClock::updateMasterBeatDistance(double beatDistance) { if (kLogger.traceEnabled()) { kLogger.trace() << "InternalClock::setMasterBeatDistance" << beatDistance; } @@ -121,7 +121,7 @@ double InternalClock::getBpm() const { return m_pClockBpm->get(); } -void InternalClock::setMasterBpm(double bpm) { +void InternalClock::updateMasterBpm(double bpm) { if (kLogger.traceEnabled()) { kLogger.trace() << "InternalClock::setBpm" << bpm; } @@ -132,7 +132,7 @@ void InternalClock::setMasterBpm(double bpm) { updateBeatLength(m_iOldSampleRate, bpm); } -void InternalClock::setInstantaneousBpm(double bpm) { +void InternalClock::updateInstantaneousBpm(double bpm) { if (kLogger.traceEnabled()) { kLogger.trace() << "InternalClock::setInstantaneousBpm" << bpm; } @@ -143,16 +143,16 @@ void InternalClock::setInstantaneousBpm(double bpm) { void InternalClock::notifyMasterParamSource() { } -void InternalClock::setMasterParams(double beatDistance, double baseBpm, double bpm) { +void InternalClock::reinitMasterParams(double beatDistance, double baseBpm, double bpm) { if (kLogger.traceEnabled()) { - kLogger.trace() << "InternalClock::setMasterParams" << beatDistance << baseBpm << bpm; + kLogger.trace() << "InternalClock::reinitMasterParams" << beatDistance << baseBpm << bpm; } if (bpm <= 0.0 || baseBpm <= 0.0) { return; } m_dBaseBpm = baseBpm; - setMasterBpm(bpm); - setMasterBeatDistance(beatDistance); + updateMasterBpm(bpm); + updateMasterBeatDistance(beatDistance); } void InternalClock::slotBaseBpmChanged(double baseBpm) { @@ -168,7 +168,7 @@ void InternalClock::slotBeatDistanceChanged(double beatDistance) { if (beatDistance < 0.0 || beatDistance > 1.0) { return; } - setMasterBeatDistance(beatDistance); + updateMasterBeatDistance(beatDistance); } void InternalClock::updateBeatLength(int sampleRate, double bpm) { @@ -204,7 +204,7 @@ void InternalClock::updateBeatLength(int sampleRate, double bpm) { m_iOldSampleRate = sampleRate; // Restore the old beat distance. - setMasterBeatDistance(oldBeatDistance); + updateMasterBeatDistance(oldBeatDistance); } void InternalClock::onCallbackStart(int sampleRate, int bufferSize) { diff --git a/src/engine/sync/internalclock.h b/src/engine/sync/internalclock.h index da0ddde7509..d27e3939fd0 100644 --- a/src/engine/sync/internalclock.h +++ b/src/engine/sync/internalclock.h @@ -48,14 +48,14 @@ class InternalClock : public QObject, public Clock, public Syncable { } double getBeatDistance() const override; - void setMasterBeatDistance(double beatDistance) override; + void updateMasterBeatDistance(double beatDistance) override; double getBaseBpm() const override; - void setMasterBpm(double bpm) override; + void updateMasterBpm(double bpm) override; void notifyMasterParamSource() override; double getBpm() const override; - void setInstantaneousBpm(double bpm) override; - void setMasterParams(double beatDistance, double baseBpm, double bpm) override; + void updateInstantaneousBpm(double bpm) override; + void reinitMasterParams(double beatDistance, double baseBpm, double bpm) override; void onCallbackStart(int sampleRate, int bufferSize); void onCallbackEnd(int sampleRate, int bufferSize); diff --git a/src/engine/sync/syncable.h b/src/engine/sync/syncable.h index 1596b378cbb..f96b0153690 100644 --- a/src/engine/sync/syncable.h +++ b/src/engine/sync/syncable.h @@ -106,26 +106,28 @@ class Syncable { // current Sync Master. // Must never result in a call to // SyncableListener::notifyBeatDistanceChanged or signal loops could occur. - virtual void setMasterBeatDistance(double beatDistance) = 0; + virtual void updateMasterBeatDistance(double beatDistance) = 0; + // Update the current playback speed (not including scratch values) + // of the current master. // Must never result in a call to SyncableListener::notifyBpmChanged or // signal loops could occur. - virtual void setMasterBpm(double bpm) = 0; + virtual void updateMasterBpm(double bpm) = 0; // Tells a Syncable that it's going to be used as a source for master // params. This is a gross hack so that the SyncControl can undo its // half/double adjustment so bpms are initialized correctly. virtual void notifyMasterParamSource() = 0; - // Combines the above three calls into one, since they are often set - // simultaneously. Avoids redundant recalculation that would occur by - // using the three calls separately. - virtual void setMasterParams(double beatDistance, double baseBpm, double bpm) = 0; + // Perform a reset of Master parameters. This function also triggers recalculation + // of half-double multiplier. + virtual void reinitMasterParams(double beatDistance, double baseBpm, double bpm) = 0; + // Update the playback speed of the master, including scratch values. // Must never result in a call to // SyncableListener::notifyInstantaneousBpmChanged or signal loops could // occur. - virtual void setInstantaneousBpm(double bpm) = 0; + virtual void updateInstantaneousBpm(double bpm) = 0; }; /// SyncableListener is an interface class used by EngineSync to receive diff --git a/src/engine/sync/synccontrol.cpp b/src/engine/sync/synccontrol.cpp index 728a51d9b39..604a55db176 100644 --- a/src/engine/sync/synccontrol.cpp +++ b/src/engine/sync/synccontrol.cpp @@ -22,8 +22,10 @@ namespace { const mixxx::Logger kLogger("SyncControl"); } // namespace -SyncControl::SyncControl(const QString& group, UserSettingsPointer pConfig, - EngineChannel* pChannel, SyncableListener* pEngineSync) +SyncControl::SyncControl(const QString& group, + UserSettingsPointer pConfig, + EngineChannel* pChannel, + SyncableListener* pEngineSync) : EngineControl(group, pConfig), m_sGroup(group), m_pChannel(pChannel), @@ -159,7 +161,7 @@ void SyncControl::requestSync() { if (isPlaying() && m_pQuantize->toBool()) { // only sync phase if the deck is playing and if quantize is enabled. // this way the it is up to the user to decide if a seek is desired or not. - // This is helpful if the beatgrid of the track doe not fit at the current + // This is helpful if the beatgrid of the track does not fit at the current // playposition m_pChannel->getEngineBuffer()->requestSyncPhase(); } @@ -177,7 +179,7 @@ double SyncControl::adjustSyncBeatDistance(double beatDistance) const { // Similar to adjusting the target beat distance, when we report our beat // distance we need to adjust it by the master bpm adjustment factor. If // we've been doubling the master bpm, we need to divide it in half. If - // we'be been halving the master bpm, we need to double it. Both operations + // we've been halving the master bpm, we need to double it. Both operations // also need to account for if the longer beat is past its halfway point. // // This is the inverse of the updateTargetBeatDistance function below. @@ -204,7 +206,7 @@ double SyncControl::getBaseBpm() const { return m_pLocalBpm->get() / m_masterBpmAdjustFactor; } -void SyncControl::setMasterBeatDistance(double beatDistance) { +void SyncControl::updateMasterBeatDistance(double beatDistance) { if (kLogger.traceEnabled()) { kLogger.trace() << getGroup() << "SyncControl::setMasterBeatDistance" << beatDistance; @@ -217,7 +219,7 @@ void SyncControl::setMasterBeatDistance(double beatDistance) { updateTargetBeatDistance(); } -void SyncControl::setMasterBpm(double bpm) { +void SyncControl::updateMasterBpm(double bpm) { if (kLogger.traceEnabled()) { kLogger.trace() << getGroup() << "SyncControl::setMasterBpm" << bpm; } @@ -242,15 +244,15 @@ void SyncControl::notifyMasterParamSource() { m_masterBpmAdjustFactor = kBpmUnity; } -void SyncControl::setMasterParams( +void SyncControl::reinitMasterParams( double beatDistance, double baseBpm, double bpm) { if (kLogger.traceEnabled()) { kLogger.trace() << "SyncControl::setMasterParams" << getGroup() << beatDistance << baseBpm << bpm; } m_masterBpmAdjustFactor = determineBpmMultiplier(fileBpm(), baseBpm); - setMasterBpm(bpm); - setMasterBeatDistance(beatDistance); + updateMasterBpm(bpm); + updateMasterBeatDistance(beatDistance); } double SyncControl::determineBpmMultiplier(double myBpm, double targetBpm) const { @@ -309,9 +311,9 @@ double SyncControl::getBpm() const { return m_pBpm->get() / m_masterBpmAdjustFactor; } -void SyncControl::setInstantaneousBpm(double bpm) { +void SyncControl::updateInstantaneousBpm(double bpm) { // Adjust the incoming bpm by the multiplier. - m_pBpmControl->setInstantaneousBpm(bpm * m_masterBpmAdjustFactor); + m_pBpmControl->updateInstantaneousBpm(bpm * m_masterBpmAdjustFactor); } void SyncControl::reportTrackPosition(double fractionalPlaypos) { diff --git a/src/engine/sync/synccontrol.h b/src/engine/sync/synccontrol.h index 69af12e6c65..1654a0208b1 100644 --- a/src/engine/sync/synccontrol.h +++ b/src/engine/sync/synccontrol.h @@ -47,17 +47,17 @@ class SyncControl : public EngineControl, public Syncable { // Must never result in a call to // SyncableListener::notifyBeatDistanceChanged or signal loops could occur. - void setMasterBeatDistance(double beatDistance) override; + void updateMasterBeatDistance(double beatDistance) override; // Must never result in a call to // SyncableListener::notifyBpmChanged or signal loops could occur. - void setMasterBpm(double bpm) override; + void updateMasterBpm(double bpm) override; void notifyMasterParamSource() override; - void setMasterParams(double beatDistance, double baseBpm, double bpm) override; + void reinitMasterParams(double beatDistance, double baseBpm, double bpm) override; // Must never result in a call to // SyncableListener::notifyInstantaneousBpmChanged or signal loops could // occur. - void setInstantaneousBpm(double bpm) override; + void updateInstantaneousBpm(double bpm) override; void setEngineControls(RateControl* pRateControl, BpmControl* pBpmControl); @@ -107,7 +107,8 @@ class SyncControl : public EngineControl, public Syncable { // When syncing, sometimes it's better to match half or double the // master bpm. FRIEND_TEST(EngineSyncTest, HalfDoubleBpmTest); - // The amount we should multiply the master BPM to find a good sync match. + FRIEND_TEST(EngineSyncTest, HalfDoubleThenPlay); + // The amount we should multiply the master BPM by to find a good sync match. // Sometimes this is 2 or 0.5. double m_masterBpmAdjustFactor; // It is handy to store the raw reported target beat distance in case the From 47cd79e4294d196a1a1c607eb27e87b841f230cb Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 15 Jun 2021 22:21:04 -0400 Subject: [PATCH 010/194] Sync Lock: Don't recalc half/double multiplier on every callback --- src/engine/sync/enginesync.cpp | 10 ++++++---- src/test/enginesynctest.cpp | 35 +++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/engine/sync/enginesync.cpp b/src/engine/sync/enginesync.cpp index 595be45439c..7be0f0fe283 100644 --- a/src/engine/sync/enginesync.cpp +++ b/src/engine/sync/enginesync.cpp @@ -415,11 +415,13 @@ void EngineSync::requestBpmUpdate(Syncable* pSyncable, double bpm) { } if (mbaseBpm != 0.0) { - // resync to current master - pSyncable->reinitMasterParams(beatDistance, mbaseBpm, mbpm); + // update from current master + pSyncable->updateMasterBeatDistance(beatDistance); + pSyncable->updateMasterBpm(mbpm); } else { - // There is no other master, adopt this bpm as master - pSyncable->reinitMasterParams(0.0, 0.0, bpm); + // There is no master, adopt this bpm as master value + pSyncable->updateMasterBeatDistance(0.0); + pSyncable->updateMasterBpm(bpm); } } diff --git a/src/test/enginesynctest.cpp b/src/test/enginesynctest.cpp index 953c9405e62..cfe50230b1e 100644 --- a/src/test/enginesynctest.cpp +++ b/src/test/enginesynctest.cpp @@ -1670,18 +1670,22 @@ TEST_F(EngineSyncTest, HalfDoubleBpmTest) { mixxx::BeatsPointer pBeats2 = BeatFactory::makeBeatGrid(m_pTrack2->getSampleRate(), 140, 0.0); m_pTrack2->trySetBeats(pBeats2); + // Mixxx will choose the first playing deck to be master. Let's start deck 2 first. + ControlObject::getControl(ConfigKey(m_sGroup1, "volume"))->set(1.0); + ControlObject::getControl(ConfigKey(m_sGroup2, "volume"))->set(1.0); + ProcessBuffer(); ControlObject::getControl(ConfigKey(m_sGroup1, "quantize"))->set(1.0); ControlObject::getControl(ConfigKey(m_sGroup2, "quantize"))->set(1.0); - ControlObject::getControl(ConfigKey(m_sGroup2, "sync_mode")) - ->set(SYNC_FOLLOWER); - ControlObject::getControl(ConfigKey(m_sGroup1, "sync_mode")) - ->set(SYNC_FOLLOWER); - - // Mixxx will choose the first playing deck to be master. Let's start deck 2 first. + ControlObject::getControl(ConfigKey(m_sGroup2, "sync_enabled"))->set(1); + ControlObject::getControl(ConfigKey(m_sGroup1, "sync_enabled"))->set(1); + ProcessBuffer(); ControlObject::getControl(ConfigKey(m_sGroup2, "play"))->set(1.0); ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0); ProcessBuffer(); + ASSERT_TRUE(isSoftMaster(m_sGroup2)); + ASSERT_TRUE(isFollower(m_sGroup1)); + EXPECT_EQ(0.5, m_pChannel1->getEngineBuffer() ->m_pSyncControl->m_masterBpmAdjustFactor); @@ -1777,9 +1781,15 @@ TEST_F(EngineSyncTest, HalfDoubleThenPlay) { ControlObject::getControl(ConfigKey(m_sGroup2, "quantize"))->set(1.0); // We expect that m_sGroup1 has adjusted its own bpm to the second deck and becomes a single master. - // When the second deck is synced the master bpm is adopted by the internal clock + // The internal clock is initialized right away. EXPECT_TRUE(isSoftMaster(m_sGroup1)); EXPECT_TRUE(isFollower(m_sGroup2)); + EXPECT_DOUBLE_EQ(1.0, + m_pChannel1->getEngineBuffer() + ->m_pSyncControl->m_masterBpmAdjustFactor); + EXPECT_DOUBLE_EQ(2.0, + m_pChannel2->getEngineBuffer() + ->m_pSyncControl->m_masterBpmAdjustFactor); EXPECT_DOUBLE_EQ(87.5, ControlObject::getControl(ConfigKey(m_sInternalClockGroup, "bpm")) ->get()); @@ -1790,9 +1800,10 @@ TEST_F(EngineSyncTest, HalfDoubleThenPlay) { EXPECT_DOUBLE_EQ(87.5 / 80, ControlObject::getControl(ConfigKey(m_sGroup1, "rate_ratio")) ->get()); - EXPECT_DOUBLE_EQ(1, + EXPECT_DOUBLE_EQ(1.0, ControlObject::getControl(ConfigKey(m_sGroup2, "rate_ratio")) ->get()); + // Local bpms are not adjusted by the multiplier EXPECT_DOUBLE_EQ(80, ControlObject::getControl(ConfigKey(m_sGroup1, "local_bpm")) ->get()); @@ -1828,13 +1839,19 @@ TEST_F(EngineSyncTest, HalfDoubleThenPlay) { ProcessBuffer(); pButtonSyncEnabled2->slotSet(1.0); pButtonSyncEnabled1->slotSet(1.0); + EXPECT_DOUBLE_EQ(0.5, + m_pChannel1->getEngineBuffer() + ->m_pSyncControl->m_masterBpmAdjustFactor); + EXPECT_DOUBLE_EQ(1.0, + m_pChannel2->getEngineBuffer() + ->m_pSyncControl->m_masterBpmAdjustFactor); ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0); ControlObject::getControl(ConfigKey(m_sGroup2, "play"))->set(1.0); EXPECT_DOUBLE_EQ(87.5 / 80, ControlObject::getControl(ConfigKey(m_sGroup1, "rate_ratio")) ->get()); - EXPECT_DOUBLE_EQ(1, + EXPECT_DOUBLE_EQ(1.0, ControlObject::getControl(ConfigKey(m_sGroup2, "rate_ratio")) ->get()); From 65ae0bfb7360a19094ba2d2fc70f018ce2de666c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 27 Jun 2021 00:39:57 +0200 Subject: [PATCH 011/194] Removed unused ColumnWidth calls, because of QHeaderView::ResizeToContents --- src/library/dlgtagfetcher.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/library/dlgtagfetcher.cpp b/src/library/dlgtagfetcher.cpp index c18e62c5794..0d82738d6ac 100644 --- a/src/library/dlgtagfetcher.cpp +++ b/src/library/dlgtagfetcher.cpp @@ -84,14 +84,6 @@ void DlgTagFetcher::init() { connect(&m_tagFetcher, &TagFetcher::resultAvailable, this, &DlgTagFetcher::fetchTagFinished); connect(&m_tagFetcher, &TagFetcher::fetchProgress, this, &DlgTagFetcher::fetchTagProgress); connect(&m_tagFetcher, &TagFetcher::networkError, this, &DlgTagFetcher::slotNetworkResult); - - // Resize columns, this can't be set in the ui file - results->setColumnWidth(0, 160); // Title column - results->setColumnWidth(1, 160); // Artist column - results->setColumnWidth(2, 160); // Album column - results->setColumnWidth(3, 50); // Year column - results->setColumnWidth(4, 50); // Track (numbers) column - results->setColumnWidth(5, 160); // Album artist column } void DlgTagFetcher::slotNext() { From f56f4cd8dba84f6caae1805c21ca6498b318c77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 27 Jun 2021 00:49:48 +0200 Subject: [PATCH 012/194] Pull latest translations from https://www.transifex.com/mixxx-dj-software/mixxxdj/mixxx2-3/. Compile QM files out of TS files that are use by the localized app --- res/translations/mixxx_de.qm | Bin 389194 -> 389731 bytes res/translations/mixxx_de.ts | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/res/translations/mixxx_de.qm b/res/translations/mixxx_de.qm index a13d33540061e4c5cca7591138a275722e4cfb17..5f248fcd7a4b8ca6a3692d3e8a54c0704deb70d6 100644 GIT binary patch delta 20168 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 Donate - + Spenden @@ -10648,7 +10648,7 @@ Ganz rechts: Ende der Effektperiode Double-click - + Doppelklick @@ -11413,7 +11413,7 @@ Ganz rechts: Ende der Effektperiode Opens separate artwork viewer. - + Öffnet separate Cover-Bild Anzeige @@ -12423,12 +12423,12 @@ Verwenden Sie diese Option, um nur das verarbeitete (Wet) Signal mit EQ- und Fil Opens the track properties editor - + Öffnet den Editor der Track-Eigenschaften Opens the track context menu. - + Öffnet das Track-Kontextmenü From 6603d6fa70389072cfaf1bc193eb2fd9eac84eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 27 Jun 2021 00:55:19 +0200 Subject: [PATCH 013/194] Pepare release candidtate by remoing beta suffix --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82a60d57a25..c8dc23e5f5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ endif() project(mixxx VERSION 2.3.0) # Work around missing version suffixes support https://gitlab.kitware.com/cmake/cmake/-/issues/16716 -set(MIXXX_VERSION_PRERELEASE "beta") # set to "alpha-pre" "beta" or "" +set(MIXXX_VERSION_PRERELEASE "") # set to "alpha-pre" "beta" or "" set(CMAKE_PROJECT_HOMEPAGE_URL "https://www.mixxx.org") set(CMAKE_PROJECT_DESCRIPTION "Mixxx is Free DJ software that gives you everything you need to perform live mixes.") From 0619056bbb73e6e9f9d7d2051cdf35798c9da6c0 Mon Sep 17 00:00:00 2001 From: ehmic <1mail4me@web.de> Date: Sun, 27 Jun 2021 10:52:01 +0200 Subject: [PATCH 014/194] MusicBrainz dialog section-resize fix plus cleanup --- src/library/dlgtagfetcher.cpp | 13 +++++-------- src/library/dlgtagfetcher.ui | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/library/dlgtagfetcher.cpp b/src/library/dlgtagfetcher.cpp index c18e62c5794..a68bc68d2ad 100644 --- a/src/library/dlgtagfetcher.cpp +++ b/src/library/dlgtagfetcher.cpp @@ -85,13 +85,6 @@ void DlgTagFetcher::init() { connect(&m_tagFetcher, &TagFetcher::fetchProgress, this, &DlgTagFetcher::fetchTagProgress); connect(&m_tagFetcher, &TagFetcher::networkError, this, &DlgTagFetcher::slotNetworkResult); - // Resize columns, this can't be set in the ui file - results->setColumnWidth(0, 160); // Title column - results->setColumnWidth(1, 160); // Artist column - results->setColumnWidth(2, 160); // Album column - results->setColumnWidth(3, 50); // Year column - results->setColumnWidth(4, 50); // Track (numbers) column - results->setColumnWidth(5, 160); // Album artist column } void DlgTagFetcher::slotNext() { @@ -307,7 +300,11 @@ void DlgTagFetcher::updateStack() { } } - results->header()->resizeSections(QHeaderView::ResizeToContents); + for (int i = 0; i < results->model()->columnCount(); i++) { + results->resizeColumnToContents(i); + int sectionSize = (results->columnWidth(i) + 10); + results->header()->resizeSection(i, sectionSize); + } // Find the item that was selected last time for (int i = 0; i < results->model()->rowCount(); ++i) { diff --git a/src/library/dlgtagfetcher.ui b/src/library/dlgtagfetcher.ui index 01b9f27da08..2caba2d16d4 100644 --- a/src/library/dlgtagfetcher.ui +++ b/src/library/dlgtagfetcher.ui @@ -46,7 +46,7 @@ 50 - false + true From a082da014e4677e69e0687b45ec17fb252966e71 Mon Sep 17 00:00:00 2001 From: ehmic <1mail4me@web.de> Date: Sun, 27 Jun 2021 11:23:07 +0200 Subject: [PATCH 015/194] cleanup --- src/library/dlgtagfetcher.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library/dlgtagfetcher.cpp b/src/library/dlgtagfetcher.cpp index a68bc68d2ad..90d0873666c 100644 --- a/src/library/dlgtagfetcher.cpp +++ b/src/library/dlgtagfetcher.cpp @@ -84,7 +84,6 @@ void DlgTagFetcher::init() { connect(&m_tagFetcher, &TagFetcher::resultAvailable, this, &DlgTagFetcher::fetchTagFinished); connect(&m_tagFetcher, &TagFetcher::fetchProgress, this, &DlgTagFetcher::fetchTagProgress); connect(&m_tagFetcher, &TagFetcher::networkError, this, &DlgTagFetcher::slotNetworkResult); - } void DlgTagFetcher::slotNext() { From 56531907b798b1200c07a8142ac9f2c28cbdefb9 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 28 Jun 2021 17:49:22 +0200 Subject: [PATCH 016/194] parented_ptr: Cast to QObject to fix parent method signature mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Classes inheriting from QAbstractItemModel are QObjects, but also have a `parent()` method that takes a QModelIndex. In these cases, an error like this may be thrown: src/util/parented_ptr.h: In instantiation of ‘parented_ptr::~parented_ptr() [with T = TreeItemModel]’: src/library/itunes/itunesfeature.cpp:67:55: required from here src/util/parented_ptr.h:31:45: error: no matching function for call to ‘TreeItemModel::parent()’ 31 | DEBUG_ASSERT(!m_ptr || m_ptr->parent()); | ~~~~~~~~~~~~~^~ This fixes the issue by casting to QObject first. --- src/util/parented_ptr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/parented_ptr.h b/src/util/parented_ptr.h index 7213fac565f..dd5d4ba2a7e 100644 --- a/src/util/parented_ptr.h +++ b/src/util/parented_ptr.h @@ -28,7 +28,7 @@ class parented_ptr final { } ~parented_ptr() noexcept { - DEBUG_ASSERT(!m_ptr || m_ptr->parent()); + DEBUG_ASSERT(!m_ptr || static_cast(m_ptr)->parent()); } // Delete copy constructor and copy assignment operator From 3cb730a5d6a687b1212f71bb858fa42490ea60dd Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 28 Jun 2021 17:54:05 +0200 Subject: [PATCH 017/194] library: Use parented_ptr for feature sidebar model instances --- src/library/analysisfeature.cpp | 2 +- src/library/analysisfeature.h | 13 +++++++------ src/library/autodj/autodjfeature.cpp | 2 +- src/library/autodj/autodjfeature.h | 3 ++- src/library/banshee/bansheefeature.cpp | 2 +- src/library/banshee/bansheefeature.h | 2 +- src/library/itunes/itunesfeature.cpp | 2 +- src/library/itunes/itunesfeature.h | 11 ++++++----- src/library/mixxxlibraryfeature.cpp | 2 +- src/library/mixxxlibraryfeature.h | 2 +- src/library/rekordbox/rekordboxfeature.cpp | 2 +- src/library/rekordbox/rekordboxfeature.h | 4 ++-- src/library/rhythmbox/rhythmboxfeature.cpp | 2 +- src/library/rhythmbox/rhythmboxfeature.h | 11 ++++++----- src/library/serato/seratofeature.cpp | 2 +- src/library/serato/seratofeature.h | 3 ++- src/library/trackset/basetracksetfeature.cpp | 2 +- src/library/trackset/basetracksetfeature.h | 3 ++- src/library/traktor/traktorfeature.cpp | 2 +- src/library/traktor/traktorfeature.h | 2 +- 20 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/library/analysisfeature.cpp b/src/library/analysisfeature.cpp index 074742427d8..b678cadfcb9 100644 --- a/src/library/analysisfeature.cpp +++ b/src/library/analysisfeature.cpp @@ -52,7 +52,7 @@ AnalysisFeature::AnalysisFeature( m_baseTitle(tr("Analyze")), m_icon(":/images/library/ic_library_prepare.svg"), m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_pAnalysisView(nullptr), m_title(m_baseTitle) { } diff --git a/src/library/analysisfeature.h b/src/library/analysisfeature.h index b447ce36e7a..cc0929d8271 100644 --- a/src/library/analysisfeature.h +++ b/src/library/analysisfeature.h @@ -1,17 +1,18 @@ #pragma once +#include +#include +#include #include #include -#include #include -#include -#include -#include "library/libraryfeature.h" +#include "analyzer/trackanalysisscheduler.h" #include "library/dlganalysis.h" +#include "library/libraryfeature.h" #include "library/treeitemmodel.h" -#include "analyzer/trackanalysisscheduler.h" #include "preferences/usersettings.h" +#include "util/parented_ptr.h" class TrackCollection; @@ -68,7 +69,7 @@ class AnalysisFeature : public LibraryFeature { TrackAnalysisScheduler::Pointer m_pTrackAnalysisScheduler; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; DlgAnalysis* m_pAnalysisView; // The title is dynamic and reflects the current progress diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index fc4b2748b26..c43c4fc992b 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -53,7 +53,7 @@ AutoDJFeature::AutoDJFeature(Library* pLibrary, m_playlistDao(m_pTrackCollection->getPlaylistDAO()), m_iAutoDJPlaylistId(findOrCrateAutoDjPlaylistId(m_playlistDao)), m_pAutoDJProcessor(nullptr), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_pAutoDJView(nullptr), m_autoDjCratesDao(m_iAutoDJPlaylistId, pLibrary->trackCollectionManager(), m_pConfig), m_icon(":/images/library/ic_library_autodj.svg") { diff --git a/src/library/autodj/autodjfeature.h b/src/library/autodj/autodjfeature.h index 7148674a922..3c54b95ebf4 100644 --- a/src/library/autodj/autodjfeature.h +++ b/src/library/autodj/autodjfeature.h @@ -16,6 +16,7 @@ #include "library/trackset/crate/crate.h" #include "library/treeitemmodel.h" #include "preferences/usersettings.h" +#include "util/parented_ptr.h" class DlgAutoDJ; class Library; @@ -62,7 +63,7 @@ class AutoDJFeature : public LibraryFeature { // The id of the AutoDJ playlist. int m_iAutoDJPlaylistId; AutoDJProcessor* m_pAutoDJProcessor; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; DlgAutoDJ* m_pAutoDJView; // Initialize the list of crates loaded into the auto-DJ queue. diff --git a/src/library/banshee/bansheefeature.cpp b/src/library/banshee/bansheefeature.cpp index dcba9297904..aae0204b0cc 100644 --- a/src/library/banshee/bansheefeature.cpp +++ b/src/library/banshee/bansheefeature.cpp @@ -18,7 +18,7 @@ QString BansheeFeature::m_databaseFile; BansheeFeature::BansheeFeature(Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_cancelImport(false), m_icon(":/images/library/ic_library_banshee.svg") { Q_UNUSED(pConfig); diff --git a/src/library/banshee/bansheefeature.h b/src/library/banshee/bansheefeature.h index ce08d717812..aa9e2ac19a5 100644 --- a/src/library/banshee/bansheefeature.h +++ b/src/library/banshee/bansheefeature.h @@ -36,7 +36,7 @@ class BansheeFeature : public BaseExternalLibraryFeature { virtual void appendTrackIdsFromRightClickIndex(QList* trackIds, QString* pPlaylist); BansheePlaylistModel* m_pBansheePlaylistModel; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; QStringList m_playlists; //a new DB connection for the worker thread diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index 0f924c0dcd9..69e64fa5560 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -64,7 +64,7 @@ QString localhost_token() { ITunesFeature::ITunesFeature(Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_cancelImport(false), m_icon(":/images/library/ic_library_itunes.svg") { QString tableName = "itunes_library"; diff --git a/src/library/itunes/itunesfeature.h b/src/library/itunes/itunesfeature.h index c0828d8f134..5c70651b913 100644 --- a/src/library/itunes/itunesfeature.h +++ b/src/library/itunes/itunesfeature.h @@ -1,16 +1,17 @@ #pragma once -#include -#include #include -#include #include #include +#include +#include +#include #include "library/baseexternallibraryfeature.h" #include "library/trackcollection.h" -#include "library/treeitemmodel.h" #include "library/treeitem.h" +#include "library/treeitemmodel.h" +#include "util/parented_ptr.h" class BaseExternalTrackModel; class BaseExternalPlaylistModel; @@ -52,7 +53,7 @@ class ITunesFeature : public BaseExternalLibraryFeature { BaseExternalTrackModel* m_pITunesTrackModel; BaseExternalPlaylistModel* m_pITunesPlaylistModel; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; QStringList m_playlists; // a new DB connection for the worker thread QSqlDatabase m_database; diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp index 2957384128c..cd936b8049a 100644 --- a/src/library/mixxxlibraryfeature.cpp +++ b/src/library/mixxxlibraryfeature.cpp @@ -75,7 +75,7 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, m_icon(":/images/library/ic_library_tracks.svg"), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_pLibraryTableModel(nullptr), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_pMissingView(nullptr), m_pHiddenView(nullptr) { QStringList columns = DEFAULT_COLUMNS; diff --git a/src/library/mixxxlibraryfeature.h b/src/library/mixxxlibraryfeature.h index 09595840a60..431e3badbd2 100644 --- a/src/library/mixxxlibraryfeature.h +++ b/src/library/mixxxlibraryfeature.h @@ -73,7 +73,7 @@ class MixxxLibraryFeature final : public LibraryFeature { QSharedPointer m_pBaseTrackCache; LibraryTableModel* m_pLibraryTableModel; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; DlgMissing* m_pMissingView; DlgHidden* m_pHiddenView; diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 61c5efc687b..5e08faffd02 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1326,7 +1326,7 @@ RekordboxFeature::RekordboxFeature( Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_icon(":/images/library/ic_library_rekordbox.svg") { QString tableName = kRekordboxLibraryTable; QString idColumn = LIBRARYTABLE_ID; diff --git a/src/library/rekordbox/rekordboxfeature.h b/src/library/rekordbox/rekordboxfeature.h index af33d88874d..d49e0432a79 100644 --- a/src/library/rekordbox/rekordboxfeature.h +++ b/src/library/rekordbox/rekordboxfeature.h @@ -28,13 +28,13 @@ #include #include #include - #include #include "library/baseexternallibraryfeature.h" #include "library/baseexternalplaylistmodel.h" #include "library/baseexternaltrackmodel.h" #include "library/treeitemmodel.h" +#include "util/parented_ptr.h" class TrackCollectionManager; class BaseExternalPlaylistModel; @@ -80,7 +80,7 @@ class RekordboxFeature : public BaseExternalLibraryFeature { QString formatRootViewHtml() const; BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; RekordboxPlaylistModel* m_pRekordboxPlaylistModel; QFutureWatcher> m_devicesFutureWatcher; diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp index aa66bf79b51..d65c3127afd 100644 --- a/src/library/rhythmbox/rhythmboxfeature.cpp +++ b/src/library/rhythmbox/rhythmboxfeature.cpp @@ -16,7 +16,7 @@ RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_cancelImport(false), m_icon(":/images/library/ic_library_rhythmbox.svg") { QString tableName = "rhythmbox_library"; diff --git a/src/library/rhythmbox/rhythmboxfeature.h b/src/library/rhythmbox/rhythmboxfeature.h index dc74bf50b15..ce59e6ba388 100644 --- a/src/library/rhythmbox/rhythmboxfeature.h +++ b/src/library/rhythmbox/rhythmboxfeature.h @@ -1,15 +1,16 @@ #pragma once +#include +#include #include -#include #include -#include #include -#include +#include #include "library/baseexternallibraryfeature.h" -#include "library/treeitemmodel.h" #include "library/trackcollection.h" +#include "library/treeitemmodel.h" +#include "util/parented_ptr.h" class BaseExternalTrackModel; class BaseExternalPlaylistModel; @@ -54,7 +55,7 @@ class RhythmboxFeature : public BaseExternalLibraryFeature { QFutureWatcher m_track_watcher; QFuture m_track_future; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; bool m_cancelImport; QSharedPointer m_trackSource; diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index 919063807e4..3f4bb09537d 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -847,7 +847,7 @@ SeratoFeature::SeratoFeature( Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_icon(":/images/library/ic_library_serato.svg") { QStringList columns; columns << LIBRARYTABLE_ID diff --git a/src/library/serato/seratofeature.h b/src/library/serato/seratofeature.h index 0bdac04cd2e..db5aa4640eb 100644 --- a/src/library/serato/seratofeature.h +++ b/src/library/serato/seratofeature.h @@ -21,6 +21,7 @@ #include "library/baseexternaltrackmodel.h" #include "library/serato/seratoplaylistmodel.h" #include "library/treeitemmodel.h" +#include "util/parented_ptr.h" class SeratoFeature : public BaseExternalLibraryFeature { Q_OBJECT @@ -50,7 +51,7 @@ class SeratoFeature : public BaseExternalLibraryFeature { QString formatRootViewHtml() const; BaseSqlTableModel* getPlaylistModelForPlaylist(const QString& playlist) override; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; SeratoPlaylistModel* m_pSeratoPlaylistModel; QFutureWatcher> m_databasesFutureWatcher; diff --git a/src/library/trackset/basetracksetfeature.cpp b/src/library/trackset/basetracksetfeature.cpp index cc0bc5b67c1..c027134cc23 100644 --- a/src/library/trackset/basetracksetfeature.cpp +++ b/src/library/trackset/basetracksetfeature.cpp @@ -8,7 +8,7 @@ BaseTrackSetFeature::BaseTrackSetFeature( const QString& rootViewName) : LibraryFeature(pLibrary, pConfig), m_rootViewName(rootViewName), - m_pSidebarModel(new TreeItemModel(this)) { + m_pSidebarModel(make_parented(this)) { } void BaseTrackSetFeature::activate() { diff --git a/src/library/trackset/basetracksetfeature.h b/src/library/trackset/basetracksetfeature.h index dd1ced11e63..294404ad1f9 100644 --- a/src/library/trackset/basetracksetfeature.h +++ b/src/library/trackset/basetracksetfeature.h @@ -1,6 +1,7 @@ #pragma once #include "library/libraryfeature.h" +#include "util/parented_ptr.h" class BaseTrackSetFeature : public LibraryFeature { Q_OBJECT @@ -19,5 +20,5 @@ class BaseTrackSetFeature : public LibraryFeature { protected: const QString m_rootViewName; - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; }; diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 7c1760126a6..17aa11b48fb 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -65,7 +65,7 @@ bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) { TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) : BaseExternalLibraryFeature(pLibrary, pConfig), - m_pSidebarModel(new TreeItemModel(this)), + m_pSidebarModel(make_parented(this)), m_cancelImport(false), m_icon(":/images/library/ic_library_traktor.svg") { QString tableName = "traktor_library"; diff --git a/src/library/traktor/traktorfeature.h b/src/library/traktor/traktorfeature.h index e2e649f2bd9..cd4243bf885 100644 --- a/src/library/traktor/traktorfeature.h +++ b/src/library/traktor/traktorfeature.h @@ -61,7 +61,7 @@ class TraktorFeature : public BaseExternalLibraryFeature { void clearTable(const QString& table_name); static QString getTraktorMusicDatabase(); // private fields - TreeItemModel* m_pSidebarModel; + parented_ptr m_pSidebarModel; // A separate db connection for the worker parsing thread QSqlDatabase m_database; TraktorTrackModel* m_pTraktorTableModel; From e11f2720c9409d3c99c1e0584be8f7f2ef99e418 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Mon, 28 Jun 2021 12:01:41 -0400 Subject: [PATCH 018/194] Traktor S3: Fix jog button light state --- res/controllers/Traktor-Kontrol-S3-hid-scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Traktor-Kontrol-S3-hid-scripts.js b/res/controllers/Traktor-Kontrol-S3-hid-scripts.js index 140b1d612ef..2cd16782952 100644 --- a/res/controllers/Traktor-Kontrol-S3-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S3-hid-scripts.js @@ -2073,7 +2073,7 @@ TraktorS3.Controller.prototype.lightDeck = function(group, sendPackets) { deck.colorOutput(0, "!PreviewTrack"); deck.colorOutput(0, "!LibraryFocus"); deck.colorOutput(0, "!MaximizeLibrary"); - deck.colorOutput(TraktorS3.JogDefaultOn, "!jogButton"); + deck.colorOutput(deck.jogToggled, "!jogButton"); if (group === "[Channel4]") { this.basicOutput(0, "[Master]", "!extButton"); } From d6eed394a1362fd2f11da550d476abf388e5e4bd Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 28 Jun 2021 20:24:50 +0200 Subject: [PATCH 019/194] SidebarModel: Add basic support for icon names --- src/library/analysisfeature.cpp | 11 +++++----- src/library/analysisfeature.h | 5 ----- src/library/autodj/autodjfeature.cpp | 9 ++------- src/library/autodj/autodjfeature.h | 3 --- src/library/banshee/bansheefeature.cpp | 9 ++------- src/library/banshee/bansheefeature.h | 2 -- src/library/baseexternallibraryfeature.cpp | 5 +++-- src/library/baseexternallibraryfeature.h | 3 ++- src/library/browse/browsefeature.cpp | 9 ++------- src/library/browse/browsefeature.h | 4 +--- src/library/itunes/itunesfeature.cpp | 9 ++------- src/library/itunes/itunesfeature.h | 2 -- src/library/libraryfeature.cpp | 10 ++++++++-- src/library/libraryfeature.h | 21 ++++++++++++++++++-- src/library/mixxxlibraryfeature.cpp | 7 +------ src/library/mixxxlibraryfeature.h | 2 -- src/library/recording/recordingfeature.cpp | 13 ++++-------- src/library/recording/recordingfeature.h | 2 -- src/library/rekordbox/rekordboxfeature.cpp | 7 +------ src/library/rekordbox/rekordboxfeature.h | 2 -- src/library/rhythmbox/rhythmboxfeature.cpp | 9 ++------- src/library/rhythmbox/rhythmboxfeature.h | 2 -- src/library/serato/seratofeature.cpp | 7 +------ src/library/serato/seratofeature.h | 2 -- src/library/sidebarmodel.cpp | 12 +++++++---- src/library/sidebarmodel.h | 6 ++++++ src/library/trackset/baseplaylistfeature.cpp | 5 +++-- src/library/trackset/baseplaylistfeature.h | 3 ++- src/library/trackset/basetracksetfeature.cpp | 5 +++-- src/library/trackset/basetracksetfeature.h | 3 ++- src/library/trackset/crate/cratefeature.cpp | 7 +------ src/library/trackset/crate/cratefeature.h | 3 --- src/library/trackset/playlistfeature.cpp | 8 ++------ src/library/trackset/playlistfeature.h | 2 -- src/library/trackset/setlogfeature.cpp | 10 +++------- src/library/trackset/setlogfeature.h | 2 -- src/library/traktor/traktorfeature.cpp | 9 ++------- src/library/traktor/traktorfeature.h | 2 -- 38 files changed, 87 insertions(+), 145 deletions(-) diff --git a/src/library/analysisfeature.cpp b/src/library/analysisfeature.cpp index 6de7480371f..2f787595c9d 100644 --- a/src/library/analysisfeature.cpp +++ b/src/library/analysisfeature.cpp @@ -48,12 +48,11 @@ AnalyzerModeFlags getAnalyzerModeFlags( AnalysisFeature::AnalysisFeature( Library* pLibrary, UserSettingsPointer pConfig) - : LibraryFeature(pLibrary, pConfig), - m_baseTitle(tr("Analyze")), - m_icon(":/images/library/ic_library_prepare.svg"), - m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), - m_pAnalysisView(nullptr), - m_title(m_baseTitle) { + : LibraryFeature(pLibrary, pConfig, QStringLiteral("prepare")), + m_baseTitle(tr("Analyze")), + m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), + m_pAnalysisView(nullptr), + m_title(m_baseTitle) { } void AnalysisFeature::resetTitle() { diff --git a/src/library/analysisfeature.h b/src/library/analysisfeature.h index f9a60047c12..dc0a5412f88 100644 --- a/src/library/analysisfeature.h +++ b/src/library/analysisfeature.h @@ -26,10 +26,6 @@ class AnalysisFeature : public LibraryFeature { return m_title; } - QIcon getIcon() override { - return m_icon; - } - bool dropAccept(const QList& urls, QObject* pSource) override; bool dragMoveAccept(const QUrl& url) override; void bindLibraryWidget(WLibrary* libraryWidget, @@ -64,7 +60,6 @@ class AnalysisFeature : public LibraryFeature { void setTitleProgress(int currentTrackNumber, int totalTracksCount); const QString m_baseTitle; - const QIcon m_icon; TrackAnalysisScheduler::Pointer m_pTrackAnalysisScheduler; diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index af4a685be9e..b94ac991af2 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -48,14 +48,13 @@ namespace { AutoDJFeature::AutoDJFeature(Library* pLibrary, UserSettingsPointer pConfig, PlayerManagerInterface* pPlayerManager) - : LibraryFeature(pLibrary, pConfig), + : LibraryFeature(pLibrary, pConfig, QStringLiteral("autodj")), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_playlistDao(m_pTrackCollection->getPlaylistDAO()), m_iAutoDJPlaylistId(findOrCrateAutoDjPlaylistId(m_playlistDao)), m_pAutoDJProcessor(nullptr), m_pAutoDJView(nullptr), - m_autoDjCratesDao(m_iAutoDJPlaylistId, pLibrary->trackCollectionManager(), m_pConfig), - m_icon(":/images/library/ic_library_autodj.svg") { + m_autoDjCratesDao(m_iAutoDJPlaylistId, pLibrary->trackCollectionManager(), m_pConfig) { qRegisterMetaType("AutoDJState"); m_pAutoDJProcessor = new AutoDJProcessor(this, m_pConfig, @@ -110,10 +109,6 @@ QVariant AutoDJFeature::title() { return tr("Auto DJ"); } -QIcon AutoDJFeature::getIcon() { - return m_icon; -} - void AutoDJFeature::bindLibraryWidget( WLibrary* libraryWidget, KeyboardEventFilter* keyboard) { diff --git a/src/library/autodj/autodjfeature.h b/src/library/autodj/autodjfeature.h index c6f3ef12a72..c4c9dab6abc 100644 --- a/src/library/autodj/autodjfeature.h +++ b/src/library/autodj/autodjfeature.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -34,7 +33,6 @@ class AutoDJFeature : public LibraryFeature { virtual ~AutoDJFeature(); QVariant title() override; - QIcon getIcon() override; bool dropAccept(const QList& urls, QObject* pSource) override; bool dragMoveAccept(const QUrl& url) override; @@ -83,7 +81,6 @@ class AutoDJFeature : public LibraryFeature { // auto-DJ list. QAction *m_pRemoveCrateFromAutoDj; - QIcon m_icon; QPointer m_pSidebarWidget; private slots: diff --git a/src/library/banshee/bansheefeature.cpp b/src/library/banshee/bansheefeature.cpp index 800b5bd7fa2..6735cea1234 100644 --- a/src/library/banshee/bansheefeature.cpp +++ b/src/library/banshee/bansheefeature.cpp @@ -17,9 +17,8 @@ const QString BansheeFeature::BANSHEE_MOUNT_KEY = "mixxx.BansheeFeature.mount"; QString BansheeFeature::m_databaseFile; BansheeFeature::BansheeFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_cancelImport(false), - m_icon(":/images/library/ic_library_banshee.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("banshee")), + m_cancelImport(false) { Q_UNUSED(pConfig); m_pBansheePlaylistModel = new BansheePlaylistModel( this, m_pLibrary->trackCollectionManager(), &m_connection); @@ -58,10 +57,6 @@ QVariant BansheeFeature::title() { return m_title; } -QIcon BansheeFeature::getIcon() { - return m_icon; -} - void BansheeFeature::activate() { //qDebug("BansheeFeature::activate()"); diff --git a/src/library/banshee/bansheefeature.h b/src/library/banshee/bansheefeature.h index 46e9bcf695c..1f8c86dfc28 100644 --- a/src/library/banshee/bansheefeature.h +++ b/src/library/banshee/bansheefeature.h @@ -24,7 +24,6 @@ class BansheeFeature : public BaseExternalLibraryFeature { static void prepareDbPath(UserSettingsPointer pConfig); virtual QVariant title(); - virtual QIcon getIcon(); virtual TreeItemModel* getChildModel(); @@ -50,7 +49,6 @@ class BansheeFeature : public BaseExternalLibraryFeature { QFuture m_future; QString m_title; bool m_cancelImport; - QIcon m_icon; static QString m_databaseFile; diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp index 36afe30291e..6492f092584 100644 --- a/src/library/baseexternallibraryfeature.cpp +++ b/src/library/baseexternallibraryfeature.cpp @@ -18,8 +18,9 @@ const mixxx::Logger kLogger("BaseExternalLibraryFeature"); BaseExternalLibraryFeature::BaseExternalLibraryFeature( Library* pLibrary, - UserSettingsPointer pConfig) - : LibraryFeature(pLibrary, pConfig), + UserSettingsPointer pConfig, + const QString& iconName) + : LibraryFeature(pLibrary, pConfig, iconName), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()) { m_pAddToAutoDJAction = make_parented(tr("Add to Auto DJ Queue (bottom)"), this); connect(m_pAddToAutoDJAction, diff --git a/src/library/baseexternallibraryfeature.h b/src/library/baseexternallibraryfeature.h index 97ab683c09c..3838f2871b3 100644 --- a/src/library/baseexternallibraryfeature.h +++ b/src/library/baseexternallibraryfeature.h @@ -16,7 +16,8 @@ class BaseExternalLibraryFeature : public LibraryFeature { public: BaseExternalLibraryFeature( Library* pLibrary, - UserSettingsPointer pConfig); + UserSettingsPointer pConfig, + const QString& iconName); ~BaseExternalLibraryFeature() override = default; public slots: diff --git a/src/library/browse/browsefeature.cpp b/src/library/browse/browsefeature.cpp index 66c375c3fbb..22ba202758c 100644 --- a/src/library/browse/browsefeature.cpp +++ b/src/library/browse/browsefeature.cpp @@ -31,12 +31,11 @@ BrowseFeature::BrowseFeature( Library* pLibrary, UserSettingsPointer pConfig, RecordingManager* pRecordingManager) - : LibraryFeature(pLibrary, pConfig), + : LibraryFeature(pLibrary, pConfig, QString("computer")), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_browseModel(this, pLibrary->trackCollectionManager(), pRecordingManager), m_proxyModel(&m_browseModel), - m_pLastRightClickedItem(nullptr), - m_icon(":/images/library/ic_library_computer.svg") { + m_pLastRightClickedItem(nullptr) { connect(this, &BrowseFeature::requestAddDir, pLibrary, @@ -213,10 +212,6 @@ void BrowseFeature::slotRemoveQuickLink() { saveQuickLinks(); } -QIcon BrowseFeature::getIcon() { - return m_icon; -} - TreeItemModel* BrowseFeature::getChildModel() { return &m_childModel; } diff --git a/src/library/browse/browsefeature.h b/src/library/browse/browsefeature.h index a90fdded19a..601eba6c3ec 100644 --- a/src/library/browse/browsefeature.h +++ b/src/library/browse/browsefeature.h @@ -30,8 +30,7 @@ class BrowseFeature : public LibraryFeature { RecordingManager* pRecordingManager); virtual ~BrowseFeature(); - QVariant title(); - QIcon getIcon(); + QVariant title() override; void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard); @@ -73,6 +72,5 @@ class BrowseFeature : public LibraryFeature { TreeItem* m_pLastRightClickedItem; TreeItem* m_pQuickLinkItem; QStringList m_quickLinkList; - QIcon m_icon; QPointer m_pSidebarWidget; }; diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp index 50ecab94783..fc451fb358d 100644 --- a/src/library/itunes/itunesfeature.cpp +++ b/src/library/itunes/itunesfeature.cpp @@ -63,9 +63,8 @@ QString localhost_token() { } // anonymous namespace ITunesFeature::ITunesFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_cancelImport(false), - m_icon(":/images/library/ic_library_itunes.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("itunes")), + m_cancelImport(false) { QString tableName = "itunes_library"; QString idColumn = "id"; QStringList columns; @@ -152,10 +151,6 @@ QVariant ITunesFeature::title() { return m_title; } -QIcon ITunesFeature::getIcon() { - return m_icon; -} - void ITunesFeature::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) { // store the sidebar widget pointer for later use in onRightClick() m_pSidebarWidget = pSidebarWidget; diff --git a/src/library/itunes/itunesfeature.h b/src/library/itunes/itunesfeature.h index a3cd26b1ffe..d7d0509b6bc 100644 --- a/src/library/itunes/itunesfeature.h +++ b/src/library/itunes/itunesfeature.h @@ -24,7 +24,6 @@ class ITunesFeature : public BaseExternalLibraryFeature { static bool isSupported(); QVariant title() override; - QIcon getIcon() override; void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; TreeItemModel* getChildModel() override; @@ -69,5 +68,4 @@ class ITunesFeature : public BaseExternalLibraryFeature { QSharedPointer m_trackSource; QPointer m_pSidebarWidget; - QIcon m_icon; }; diff --git a/src/library/libraryfeature.cpp b/src/library/libraryfeature.cpp index 20de2aa3189..51ad6ae3fac 100644 --- a/src/library/libraryfeature.cpp +++ b/src/library/libraryfeature.cpp @@ -15,15 +15,21 @@ namespace { const mixxx::Logger kLogger("LibraryFeature"); +const QString kIconPath = QStringLiteral(":/images/library/ic_library_%1.svg"); } // anonymous namespace LibraryFeature::LibraryFeature( Library* pLibrary, - UserSettingsPointer pConfig) + UserSettingsPointer pConfig, + const QString& iconName) : QObject(pLibrary), m_pLibrary(pLibrary), - m_pConfig(pConfig) { + m_pConfig(pConfig), + m_iconName(iconName) { + if (!m_iconName.isEmpty()) { + m_icon = QIcon(kIconPath.arg(m_iconName)); + } } QStringList LibraryFeature::getPlaylistFiles(QFileDialog::FileMode mode) const { diff --git a/src/library/libraryfeature.h b/src/library/libraryfeature.h index 465b48c23f2..26532b00384 100644 --- a/src/library/libraryfeature.h +++ b/src/library/libraryfeature.h @@ -29,11 +29,25 @@ class LibraryFeature : public QObject { public: LibraryFeature( Library* pLibrary, - UserSettingsPointer pConfig); + UserSettingsPointer pConfig, + const QString& iconName); ~LibraryFeature() override = default; virtual QVariant title() = 0; - virtual QIcon getIcon() = 0; + + /// Returns the icon name. + /// + /// This is useful for QML skins that need to build a URL anyway and may use their own icon theme. + QString iconName() const { + return m_iconName; + } + + /// Returns the icon. + /// + /// This is used by legacy QWidget skins that display a QIcon directly. + QIcon icon() const { + return m_icon; + } virtual bool dropAccept(const QList& urls, QObject* pSource) { Q_UNUSED(urls); @@ -134,4 +148,7 @@ class LibraryFeature : public QObject { private: QStringList getPlaylistFiles(QFileDialog::FileMode mode) const; + + QString m_iconName; + QIcon m_icon; }; diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp index 83f80252307..cb2c71159d7 100644 --- a/src/library/mixxxlibraryfeature.cpp +++ b/src/library/mixxxlibraryfeature.cpp @@ -69,10 +69,9 @@ const QStringList DEFAULT_COLUMNS = { MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary, UserSettingsPointer pConfig) - : LibraryFeature(pLibrary, pConfig), + : LibraryFeature(pLibrary, pConfig, QStringLiteral("tracks")), kMissingTitle(tr("Missing Tracks")), kHiddenTitle(tr("Hidden Tracks")), - m_icon(":/images/library/ic_library_tracks.svg"), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_pLibraryTableModel(nullptr), m_pMissingView(nullptr), @@ -144,10 +143,6 @@ QVariant MixxxLibraryFeature::title() { return tr("Tracks"); } -QIcon MixxxLibraryFeature::getIcon() { - return m_icon; -} - TreeItemModel* MixxxLibraryFeature::getChildModel() { return &m_childModel; } diff --git a/src/library/mixxxlibraryfeature.h b/src/library/mixxxlibraryfeature.h index c84d29c38c3..3751cbcbe74 100644 --- a/src/library/mixxxlibraryfeature.h +++ b/src/library/mixxxlibraryfeature.h @@ -34,7 +34,6 @@ class MixxxLibraryFeature final : public LibraryFeature { ~MixxxLibraryFeature() override = default; QVariant title() override; - QIcon getIcon() override; bool dropAccept(const QList& urls, QObject* pSource) override; bool dragMoveAccept(const QUrl& url) override; TreeItemModel* getChildModel() override; @@ -67,7 +66,6 @@ class MixxxLibraryFeature final : public LibraryFeature { private: const QString kMissingTitle; const QString kHiddenTitle; - const QIcon m_icon; TrackCollection* const m_pTrackCollection; QSharedPointer m_pBaseTrackCache; diff --git a/src/library/recording/recordingfeature.cpp b/src/library/recording/recordingfeature.cpp index 43655334291..b473f3f834c 100644 --- a/src/library/recording/recordingfeature.cpp +++ b/src/library/recording/recordingfeature.cpp @@ -16,21 +16,16 @@ const QString kViewName = QStringLiteral("Recording"); } // anonymous namespace RecordingFeature::RecordingFeature(Library* pLibrary, - UserSettingsPointer pConfig, - RecordingManager* pRecordingManager) - : LibraryFeature(pLibrary, pConfig), - m_pRecordingManager(pRecordingManager), - m_icon(":/images/library/ic_library_recordings.svg") { + UserSettingsPointer pConfig, + RecordingManager* pRecordingManager) + : LibraryFeature(pLibrary, pConfig, QStringLiteral("recordings")), + m_pRecordingManager(pRecordingManager) { } QVariant RecordingFeature::title() { return QVariant(tr("Recordings")); } -QIcon RecordingFeature::getIcon() { - return m_icon; -} - TreeItemModel* RecordingFeature::getChildModel() { return &m_childModel; } diff --git a/src/library/recording/recordingfeature.h b/src/library/recording/recordingfeature.h index 61b26ad7821..221b305a3cd 100644 --- a/src/library/recording/recordingfeature.h +++ b/src/library/recording/recordingfeature.h @@ -20,7 +20,6 @@ class RecordingFeature final : public LibraryFeature { ~RecordingFeature() override = default; QVariant title() override; - QIcon getIcon() override; void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; @@ -37,7 +36,6 @@ class RecordingFeature final : public LibraryFeature { private: RecordingManager* const m_pRecordingManager; - const QIcon m_icon; FolderTreeModel m_childModel; }; diff --git a/src/library/rekordbox/rekordboxfeature.cpp b/src/library/rekordbox/rekordboxfeature.cpp index 0e7a0d01552..e0b6b38fdb9 100644 --- a/src/library/rekordbox/rekordboxfeature.cpp +++ b/src/library/rekordbox/rekordboxfeature.cpp @@ -1325,8 +1325,7 @@ bool RekordboxPlaylistModel::isColumnInternal(int column) { RekordboxFeature::RekordboxFeature( Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_icon(":/images/library/ic_library_rekordbox.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("rekordbox")) { QString tableName = kRekordboxLibraryTable; QString idColumn = LIBRARYTABLE_ID; QStringList columns; @@ -1438,10 +1437,6 @@ QVariant RekordboxFeature::title() { return m_title; } -QIcon RekordboxFeature::getIcon() { - return m_icon; -} - bool RekordboxFeature::isSupported() { return true; } diff --git a/src/library/rekordbox/rekordboxfeature.h b/src/library/rekordbox/rekordboxfeature.h index c1388cef3f1..247148a87c6 100644 --- a/src/library/rekordbox/rekordboxfeature.h +++ b/src/library/rekordbox/rekordboxfeature.h @@ -59,7 +59,6 @@ class RekordboxFeature : public BaseExternalLibraryFeature { ~RekordboxFeature() override; QVariant title() override; - QIcon getIcon() override; static bool isSupported(); void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; @@ -90,5 +89,4 @@ class RekordboxFeature : public BaseExternalLibraryFeature { QString m_title; QSharedPointer m_trackSource; - QIcon m_icon; }; diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp index 5607d112585..3382c7e4ddf 100644 --- a/src/library/rhythmbox/rhythmboxfeature.cpp +++ b/src/library/rhythmbox/rhythmboxfeature.cpp @@ -15,9 +15,8 @@ #include "moc_rhythmboxfeature.cpp" RhythmboxFeature::RhythmboxFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_cancelImport(false), - m_icon(":/images/library/ic_library_rhythmbox.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("rhythmbox")), + m_cancelImport(false) { QString tableName = "rhythmbox_library"; QString idColumn = "id"; QStringList columns; @@ -108,10 +107,6 @@ QVariant RhythmboxFeature::title() { return m_title; } -QIcon RhythmboxFeature::getIcon() { - return m_icon; -} - TreeItemModel* RhythmboxFeature::getChildModel() { return &m_childModel; } diff --git a/src/library/rhythmbox/rhythmboxfeature.h b/src/library/rhythmbox/rhythmboxfeature.h index fd2ef67f76c..413b59b5df0 100644 --- a/src/library/rhythmbox/rhythmboxfeature.h +++ b/src/library/rhythmbox/rhythmboxfeature.h @@ -22,7 +22,6 @@ class RhythmboxFeature : public BaseExternalLibraryFeature { static bool isSupported(); QVariant title(); - QIcon getIcon(); TreeItemModel* getChildModel(); // processes the music collection @@ -58,5 +57,4 @@ class RhythmboxFeature : public BaseExternalLibraryFeature { bool m_cancelImport; QSharedPointer m_trackSource; - QIcon m_icon; }; diff --git a/src/library/serato/seratofeature.cpp b/src/library/serato/seratofeature.cpp index b9fe1182e74..8d30c585208 100644 --- a/src/library/serato/seratofeature.cpp +++ b/src/library/serato/seratofeature.cpp @@ -846,8 +846,7 @@ bool dropTable(QSqlDatabase& database, const QString& tableName) { SeratoFeature::SeratoFeature( Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_icon(":/images/library/ic_library_serato.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("serato")) { QStringList columns; columns << LIBRARYTABLE_ID << LIBRARYTABLE_TITLE @@ -959,10 +958,6 @@ QVariant SeratoFeature::title() { return m_title; } -QIcon SeratoFeature::getIcon() { - return m_icon; -} - bool SeratoFeature::isSupported() { return true; } diff --git a/src/library/serato/seratofeature.h b/src/library/serato/seratofeature.h index 515add942e8..4ea7abe4642 100644 --- a/src/library/serato/seratofeature.h +++ b/src/library/serato/seratofeature.h @@ -29,7 +29,6 @@ class SeratoFeature : public BaseExternalLibraryFeature { ~SeratoFeature() override; QVariant title() override; - QIcon getIcon() override; static bool isSupported(); void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; @@ -60,5 +59,4 @@ class SeratoFeature : public BaseExternalLibraryFeature { QString m_title; QSharedPointer m_trackSource; - QIcon m_icon; }; diff --git a/src/library/sidebarmodel.cpp b/src/library/sidebarmodel.cpp index eabd0f09213..fc3401b6f3f 100644 --- a/src/library/sidebarmodel.cpp +++ b/src/library/sidebarmodel.cpp @@ -229,7 +229,9 @@ QVariant SidebarModel::data(const QModelIndex& index, int role) const { if (role == Qt::DisplayRole) { return m_sFeatures[index.row()]->title(); } else if (role == Qt::DecorationRole) { - return m_sFeatures[index.row()]->getIcon(); + return m_sFeatures[index.row()]->icon(); + } else if (role == SidebarModel::IconNameRole) { + return m_sFeatures[index.row()]->iconName(); } } @@ -246,15 +248,17 @@ QVariant SidebarModel::data(const QModelIndex& index, int role) const { } else { return pTreeItem->getData(); } - } else if (role == TreeItemModel::kDataRole) { - // We use Qt::UserRole to ask for the datapath. - return pTreeItem->getData(); } else if (role == Qt::FontRole) { QFont font; font.setBold(pTreeItem->isBold()); return font; } else if (role == Qt::DecorationRole) { return pTreeItem->getIcon(); + } else if (role == SidebarModel::DataRole) { + return pTreeItem->getData(); + } else if (role == SidebarModel::IconNameRole) { + // TODO: Add support for icon names in tree items + return QString(); } } } diff --git a/src/library/sidebarmodel.h b/src/library/sidebarmodel.h index 25cee03ecf0..c6d05611ebb 100644 --- a/src/library/sidebarmodel.h +++ b/src/library/sidebarmodel.h @@ -15,6 +15,12 @@ class SidebarModel : public QAbstractItemModel { // for parented_ptr using QObject::parent; + enum Roles { + IconNameRole = Qt::UserRole + 1, + DataRole, + }; + Q_ENUM(Roles); + explicit SidebarModel( QObject* parent = nullptr); ~SidebarModel() override = default; diff --git a/src/library/trackset/baseplaylistfeature.cpp b/src/library/trackset/baseplaylistfeature.cpp index 47360198064..422aadf6006 100644 --- a/src/library/trackset/baseplaylistfeature.cpp +++ b/src/library/trackset/baseplaylistfeature.cpp @@ -31,8 +31,9 @@ constexpr QChar kUnsafeFilenameReplacement = '-'; BasePlaylistFeature::BasePlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig, PlaylistTableModel* pModel, - const QString& rootViewName) - : BaseTrackSetFeature(pLibrary, pConfig, rootViewName), + const QString& rootViewName, + const QString& iconName) + : BaseTrackSetFeature(pLibrary, pConfig, rootViewName, iconName), m_playlistDao(pLibrary->trackCollectionManager() ->internalCollection() ->getPlaylistDAO()), diff --git a/src/library/trackset/baseplaylistfeature.h b/src/library/trackset/baseplaylistfeature.h index 60b18cb9a33..32c67470dc1 100644 --- a/src/library/trackset/baseplaylistfeature.h +++ b/src/library/trackset/baseplaylistfeature.h @@ -30,7 +30,8 @@ class BasePlaylistFeature : public BaseTrackSetFeature { BasePlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig, PlaylistTableModel* pModel, - const QString& rootViewName); + const QString& rootViewName, + const QString& iconName); ~BasePlaylistFeature() override = default; TreeItemModel* getChildModel() override; diff --git a/src/library/trackset/basetracksetfeature.cpp b/src/library/trackset/basetracksetfeature.cpp index 35d7d407351..951c7cf4dba 100644 --- a/src/library/trackset/basetracksetfeature.cpp +++ b/src/library/trackset/basetracksetfeature.cpp @@ -5,8 +5,9 @@ BaseTrackSetFeature::BaseTrackSetFeature( Library* pLibrary, UserSettingsPointer pConfig, - const QString& rootViewName) - : LibraryFeature(pLibrary, pConfig), + const QString& rootViewName, + const QString& iconName) + : LibraryFeature(pLibrary, pConfig, iconName), m_rootViewName(rootViewName) { } diff --git a/src/library/trackset/basetracksetfeature.h b/src/library/trackset/basetracksetfeature.h index 37a4e8b77f5..8d1ddc67e50 100644 --- a/src/library/trackset/basetracksetfeature.h +++ b/src/library/trackset/basetracksetfeature.h @@ -8,7 +8,8 @@ class BaseTrackSetFeature : public LibraryFeature { public: BaseTrackSetFeature(Library* pLibrary, UserSettingsPointer pConfig, - const QString& rootViewName); + const QString& rootViewName, + const QString& iconName); signals: void analyzeTracks(const QList&); diff --git a/src/library/trackset/crate/cratefeature.cpp b/src/library/trackset/crate/cratefeature.cpp index e2669811de3..e20d9e5615c 100644 --- a/src/library/trackset/crate/cratefeature.cpp +++ b/src/library/trackset/crate/cratefeature.cpp @@ -41,8 +41,7 @@ QString formatLabel( CrateFeature::CrateFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseTrackSetFeature(pLibrary, pConfig, "CRATEHOME"), - m_cratesIcon(":/images/library/ic_library_crates.svg"), + : BaseTrackSetFeature(pLibrary, pConfig, "CRATEHOME", QStringLiteral("crates")), m_lockedCrateIcon(":/images/library/ic_library_locked_tracklist.svg"), m_pTrackCollection(pLibrary->trackCollectionManager()->internalCollection()), m_crateTableModel(this, pLibrary->trackCollectionManager()) { @@ -174,10 +173,6 @@ QVariant CrateFeature::title() { return tr("Crates"); } -QIcon CrateFeature::getIcon() { - return m_cratesIcon; -} - QString CrateFeature::formatRootViewHtml() const { QString cratesTitle = tr("Crates"); QString cratesSummary = diff --git a/src/library/trackset/crate/cratefeature.h b/src/library/trackset/crate/cratefeature.h index 2b1d77c5047..da0c9e0ea8a 100644 --- a/src/library/trackset/crate/cratefeature.h +++ b/src/library/trackset/crate/cratefeature.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -30,7 +29,6 @@ class CrateFeature : public BaseTrackSetFeature { ~CrateFeature() override = default; QVariant title() override; - QIcon getIcon() override; bool dropAcceptChild(const QModelIndex& index, const QList& urls, @@ -98,7 +96,6 @@ class CrateFeature : public BaseTrackSetFeature { QString formatRootViewHtml() const; - const QIcon m_cratesIcon; const QIcon m_lockedCrateIcon; TrackCollection* const m_pTrackCollection; diff --git a/src/library/trackset/playlistfeature.cpp b/src/library/trackset/playlistfeature.cpp index 3d9a42df80a..859ea94fcf2 100644 --- a/src/library/trackset/playlistfeature.cpp +++ b/src/library/trackset/playlistfeature.cpp @@ -42,8 +42,8 @@ PlaylistFeature::PlaylistFeature(Library* pLibrary, UserSettingsPointer pConfig) new PlaylistTableModel(nullptr, pLibrary->trackCollectionManager(), "mixxx.db.model.playlist"), - QStringLiteral("PLAYLISTHOME")), - m_icon(QStringLiteral(":/images/library/ic_library_playlist.svg")) { + QStringLiteral("PLAYLISTHOME"), + QStringLiteral("playlist")) { // construct child model std::unique_ptr pRootItem = TreeItem::newRoot(this); m_childModel.setRootItem(std::move(pRootItem)); @@ -54,10 +54,6 @@ QVariant PlaylistFeature::title() { return tr("Playlists"); } -QIcon PlaylistFeature::getIcon() { - return m_icon; -} - void PlaylistFeature::onRightClick(const QPoint& globalPos) { m_lastRightClickedIndex = QModelIndex(); QMenu menu(m_pSidebarWidget); diff --git a/src/library/trackset/playlistfeature.h b/src/library/trackset/playlistfeature.h index 2fe64869d8c..66e1f39638b 100644 --- a/src/library/trackset/playlistfeature.h +++ b/src/library/trackset/playlistfeature.h @@ -25,7 +25,6 @@ class PlaylistFeature : public BasePlaylistFeature { ~PlaylistFeature() override = default; QVariant title() override; - QIcon getIcon() override; bool dropAcceptChild(const QModelIndex& index, const QList& urls, @@ -49,5 +48,4 @@ class PlaylistFeature : public BasePlaylistFeature { private: QString getRootViewHtml() const override; - const QIcon m_icon; }; diff --git a/src/library/trackset/setlogfeature.cpp b/src/library/trackset/setlogfeature.cpp index bc5bdd0f60c..2def95708a9 100644 --- a/src/library/trackset/setlogfeature.cpp +++ b/src/library/trackset/setlogfeature.cpp @@ -35,9 +35,9 @@ SetlogFeature::SetlogFeature( pLibrary->trackCollectionManager(), "mixxx.db.model.setlog", /*keep deleted tracks*/ true), - QStringLiteral("SETLOGHOME")), - m_playlistId(kInvalidPlaylistId), - m_icon(QStringLiteral(":/images/library/ic_library_history.svg")) { + QStringLiteral("SETLOGHOME"), + QStringLiteral("history")), + m_playlistId(kInvalidPlaylistId) { // clear old empty entries ScopedTransaction transaction(pLibrary->trackCollectionManager() ->internalCollection() @@ -79,10 +79,6 @@ QVariant SetlogFeature::title() { return tr("History"); } -QIcon SetlogFeature::getIcon() { - return m_icon; -} - void SetlogFeature::bindLibraryWidget( WLibrary* libraryWidget, KeyboardEventFilter* keyboard) { BasePlaylistFeature::bindLibraryWidget(libraryWidget, keyboard); diff --git a/src/library/trackset/setlogfeature.h b/src/library/trackset/setlogfeature.h index 07731a6b73f..a477a61be25 100644 --- a/src/library/trackset/setlogfeature.h +++ b/src/library/trackset/setlogfeature.h @@ -16,7 +16,6 @@ class SetlogFeature : public BasePlaylistFeature { virtual ~SetlogFeature(); QVariant title() override; - QIcon getIcon() override; void bindLibraryWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) override; @@ -49,5 +48,4 @@ class SetlogFeature : public BasePlaylistFeature { QAction* m_pStartNewPlaylist; int m_playlistId; QPointer m_libraryWidget; - const QIcon m_icon; }; diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp index 94760a3b3d2..ec8de08ab18 100644 --- a/src/library/traktor/traktorfeature.cpp +++ b/src/library/traktor/traktorfeature.cpp @@ -64,9 +64,8 @@ bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) { } TraktorFeature::TraktorFeature(Library* pLibrary, UserSettingsPointer pConfig) - : BaseExternalLibraryFeature(pLibrary, pConfig), - m_cancelImport(false), - m_icon(":/images/library/ic_library_traktor.svg") { + : BaseExternalLibraryFeature(pLibrary, pConfig, QStringLiteral("traktor")), + m_cancelImport(false) { QString tableName = "traktor_library"; QString idColumn = "id"; QStringList columns; @@ -143,10 +142,6 @@ QVariant TraktorFeature::title() { return m_title; } -QIcon TraktorFeature::getIcon() { - return m_icon; -} - bool TraktorFeature::isSupported() { return (QFile::exists(getTraktorMusicDatabase())); } diff --git a/src/library/traktor/traktorfeature.h b/src/library/traktor/traktorfeature.h index b685eb11937..13d42794a8f 100644 --- a/src/library/traktor/traktorfeature.h +++ b/src/library/traktor/traktorfeature.h @@ -35,7 +35,6 @@ class TraktorFeature : public BaseExternalLibraryFeature { virtual ~TraktorFeature(); QVariant title() override; - QIcon getIcon() override; static bool isSupported(); TreeItemModel* getChildModel() override; @@ -74,5 +73,4 @@ class TraktorFeature : public BaseExternalLibraryFeature { QString m_title; QSharedPointer m_trackSource; - QIcon m_icon; }; From 002b9c8a8993f19bd64cfa2ea6ec46b48f5a17df Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 28 Jun 2021 21:22:48 +0200 Subject: [PATCH 020/194] BrowseFeature: Add missing overrides --- src/library/browse/browsefeature.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/library/browse/browsefeature.h b/src/library/browse/browsefeature.h index 601eba6c3ec..3a4cb32a0e3 100644 --- a/src/library/browse/browsefeature.h +++ b/src/library/browse/browsefeature.h @@ -33,19 +33,19 @@ class BrowseFeature : public LibraryFeature { QVariant title() override; void bindLibraryWidget(WLibrary* libraryWidget, - KeyboardEventFilter* keyboard); - void bindSidebarWidget(WLibrarySidebar* pSidebarWidget); + KeyboardEventFilter* keyboard) override; + void bindSidebarWidget(WLibrarySidebar* pSidebarWidget) override; - TreeItemModel* getChildModel(); + TreeItemModel* getChildModel() override; public slots: void slotAddQuickLink(); void slotRemoveQuickLink(); void slotAddToLibrary(); - void activate(); - void activateChild(const QModelIndex& index); - void onRightClickChild(const QPoint& globalPos, const QModelIndex& index); - void onLazyChildExpandation(const QModelIndex& index); + void activate() override; + void activateChild(const QModelIndex& index) override; + void onRightClickChild(const QPoint& globalPos, const QModelIndex& index) override; + void onLazyChildExpandation(const QModelIndex& index) override; void slotLibraryScanStarted(); void slotLibraryScanFinished(); From d1dca4785af375af8f73b5ee5389311f4a4ef5e6 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 28 Jun 2021 22:04:59 +0200 Subject: [PATCH 021/194] CHANGELOG: Remove "(Unreleased)" from 2.3.0 changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e426a941d51..97d738f38ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [2.3.0](https://launchpad.net/mixxx/+milestone/2.3.0) (Unreleased) +## [2.3.0](https://launchpad.net/mixxx/+milestone/2.3.0) ### Hotcues ### * Add hotcue colors and custom labels by right clicking hotcue buttons or right clicking hotcues on overview waveforms [#2016](https://github.com/mixxxdj/mixxx/pull/2016) [#2520](https://github.com/mixxxdj/mixxx/pull/2520) [#2238](https://github.com/mixxxdj/mixxx/pull/2238) [#2560](https://github.com/mixxxdj/mixxx/pull/2560) [#2557](https://github.com/mixxxdj/mixxx/pull/2557) [#2362](https://github.com/mixxxdj/mixxx/pull/2362) * Mouse hover cues on overview waveform to show time remaining until the cue [#2238](https://github.com/mixxxdj/mixxx/pull/2238) From c1ac5772641de71ea25dfc22f4eecdf130bc354d Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 28 Jun 2021 23:18:24 +0200 Subject: [PATCH 022/194] CI: Remove "mixxx-" prefix from tag deploy path --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f8408c15ff..03434116642 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -373,7 +373,7 @@ jobs: run: > if [[ "${GITHUB_REF}" =~ ^refs/tags/.* ]]; then - export DEPLOY_PATH='releases/mixxx-{git_describe}/mixxx-{git_describe}-{package_slug}{ext}'; + export DEPLOY_PATH='releases/{git_describe}/mixxx-{git_describe}-{package_slug}{ext}'; else export DEPLOY_PATH='snapshots/{git_branch}/mixxx-{git_describe}-{package_slug}{ext}'; fi; @@ -444,7 +444,7 @@ jobs: run: > if [[ "${GITHUB_REF}" =~ ^refs/tags/.* ]]; then - export DEPLOY_PATH='releases/mixxx-{git_describe}/manifest.json'; + export DEPLOY_PATH='releases/{git_describe}/manifest.json'; else export DEPLOY_PATH='snapshots/{git_branch}/manifest.json'; fi; From 271cea58f41144b731ec0ed0d6e1f4649553a0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 24 Jun 2021 01:29:25 +0200 Subject: [PATCH 023/194] Remove int reference and skip argument parsing when no argument is given --- src/util/cmdlineargs.cpp | 6 +++++- src/util/cmdlineargs.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util/cmdlineargs.cpp b/src/util/cmdlineargs.cpp index 0cbc2d386bf..bf3000b9bf2 100644 --- a/src/util/cmdlineargs.cpp +++ b/src/util/cmdlineargs.cpp @@ -63,7 +63,11 @@ bool parseLogLevel( } } // namespace -bool CmdlineArgs::parse(int& argc, char** argv) { +bool CmdlineArgs::parse(int argc, char** argv) { + if (argc == 1) { + // We have got the binary name only, noting to do + return true; + } QStringList arguments; arguments.reserve(argc); for (int a = 0; a < argc; ++a) { diff --git a/src/util/cmdlineargs.h b/src/util/cmdlineargs.h index 046351052c2..b02615062be 100644 --- a/src/util/cmdlineargs.h +++ b/src/util/cmdlineargs.h @@ -21,7 +21,7 @@ class CmdlineArgs final { return cla; } - bool parse(int& argc, char** argv); + bool parse(int argc, char** argv); const QList& getMusicFiles() const { return m_musicFiles; } bool getStartInFullscreen() const { return m_startInFullscreen; } From e48b971f405b4c2471c96069308189cc3b5f4d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 29 Jun 2021 09:44:45 +0200 Subject: [PATCH 024/194] Use "CmdlineArges" as translation context --- src/util/cmdlineargs.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/util/cmdlineargs.cpp b/src/util/cmdlineargs.cpp index bf3000b9bf2..393642942a8 100644 --- a/src/util/cmdlineargs.cpp +++ b/src/util/cmdlineargs.cpp @@ -75,7 +75,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { } QCommandLineParser parser; - parser.setApplicationDescription(QCoreApplication::translate("main", + parser.setApplicationDescription(QCoreApplication::translate("CmdlineArgs", "Mixxx is an open source DJ software. For more information, " "see " MIXXX_MANUAL_COMMANDLINEOPTIONS_URL "\n." @@ -86,11 +86,11 @@ bool CmdlineArgs::parse(int argc, char** argv) { const QCommandLineOption fullscreen(QStringList() << "f" << "full-screen" << "fullScreen", - QCoreApplication::translate("main", "Starts Mixxx in full-screen mode")); + QCoreApplication::translate("CmdlineArgs", "Starts Mixxx in full-screen mode")); parser.addOption(fullscreen); const QCommandLineOption locale(QStringLiteral("locale"), - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Use a custom locale for loading translations. (e.g " "'fr')")); parser.addOption(locale); @@ -98,7 +98,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { // An option with a value const QCommandLineOption settingsPath(QStringList() << "settings-path" << "settingsPath", - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Top-level directory where Mixxx should look for settings. " "Default is:") + getSettingsPath().toLocal8Bit().constData(), @@ -107,7 +107,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { QCommandLineOption resourcePath(QStringList() << "resource-path" << "resourcePath", - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Top-level directory where Mixxx should look for its " "resource files such as MIDI mappings, overriding the " "default installation location."), @@ -116,34 +116,34 @@ bool CmdlineArgs::parse(int argc, char** argv) { const QCommandLineOption timelinePath(QStringList() << "timeline-path" << "timelinePath", - QCoreApplication::translate("main", "Path the timeline is written to")); + QCoreApplication::translate("CmdlineArgs", "Path the timeline is written to")); parser.addOption(timelinePath); const QCommandLineOption controllerDebug(QStringList() << "controller-debug" << "controllerDebug" << "midi-debug" << "midiDebug", - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Causes Mixxx to display/log all of the controller data it " "receives and script functions it loads")); parser.addOption(controllerDebug); const QCommandLineOption developer(QStringLiteral("developer"), - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Enables developer-mode. Includes extra log info, stats on " "performance, and a Developer tools menu.")); parser.addOption(developer); const QCommandLineOption safeMode(QStringList() << "safe-mode" << "safeMode", - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Enables safe-mode. Disables OpenGL waveforms, and " "spinning vinyl widgets. Try this option if Mixxx is " "crashing on startup.")); parser.addOption(safeMode); const QCommandLineOption color(QStringLiteral("color"), - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "[auto|always|never] Use colors on the console output."), QStringLiteral("color"), QStringLiteral("auto")); @@ -151,7 +151,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { const QCommandLineOption logLevel(QStringList() << "log-level" << "logLevel", - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Sets the verbosity of command line logging.\n" "critical - Critical/Fatal only\n" "warning - Above + Warnings\n" @@ -163,7 +163,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { const QCommandLineOption logFlushLevel(QStringList() << "log-flush-level" << "logFlushLevel", - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Sets the the logging level at which the log buffer is " "flushed to mixxx.log. LEVEL is one of the values defined " "at --logLevel above."), @@ -173,7 +173,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { #ifdef MIXXX_BUILD_DEBUG QCommandLineOption debugAssertBreak(QStringList() << "debug-assert-break" << "debugAssertBreak", - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to " "false. Under a debugger you can continue afterwards.")); parser.addOption(debugAssertBreak); @@ -183,7 +183,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { const QCommandLineOption versionOption = parser.addVersionOption(); parser.addPositionalArgument(QStringLiteral("file"), - QCoreApplication::translate("main", + QCoreApplication::translate("CmdlineArgs", "Load the specified music file(s) at start-up. Each file " "you specify will be loaded into the next virtual deck.")); From 2e12617115e82a82e176c87857f13b6ed8aa824d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 29 Jun 2021 09:59:32 +0200 Subject: [PATCH 025/194] hide deprecated command line arguments --- src/util/cmdlineargs.cpp | 132 ++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 44 deletions(-) diff --git a/src/util/cmdlineargs.cpp b/src/util/cmdlineargs.cpp index 393642942a8..98253ff6ec5 100644 --- a/src/util/cmdlineargs.cpp +++ b/src/util/cmdlineargs.cpp @@ -75,19 +75,23 @@ bool CmdlineArgs::parse(int argc, char** argv) { } QCommandLineParser parser; - parser.setApplicationDescription(QCoreApplication::translate("CmdlineArgs", - "Mixxx is an open source DJ software. For more information, " - "see " MIXXX_MANUAL_COMMANDLINEOPTIONS_URL - "\n." - "CamelCase arguments are deprecated and will be removed in 2.5")); parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + parser.setApplicationDescription( + QCoreApplication::translate("CmdlineArgs", + "Mixxx is an open source DJ software. For more " + "information, see: ") + + MIXXX_MANUAL_COMMANDLINEOPTIONS_URL); + // add options - const QCommandLineOption fullscreen(QStringList() << "f" - << "full-screen" - << "fullScreen", - QCoreApplication::translate("CmdlineArgs", "Starts Mixxx in full-screen mode")); - parser.addOption(fullscreen); + const QCommandLineOption fullScreen( + QStringList({QStringLiteral("f"), QStringLiteral("full-screen")}), + QCoreApplication::translate( + "CmdlineArgs", "Starts Mixxx in full-screen mode")); + QCommandLineOption fullScreenDeprecated(QStringLiteral("fullScreen")); + fullScreenDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); + parser.addOption(fullScreen); + parser.addOption(fullScreenDeprecated); const QCommandLineOption locale(QStringLiteral("locale"), QCoreApplication::translate("CmdlineArgs", @@ -96,37 +100,50 @@ bool CmdlineArgs::parse(int argc, char** argv) { parser.addOption(locale); // An option with a value - const QCommandLineOption settingsPath(QStringList() << "settings-path" - << "settingsPath", + const QCommandLineOption settingsPath(QStringLiteral("settings-path"), QCoreApplication::translate("CmdlineArgs", "Top-level directory where Mixxx should look for settings. " "Default is:") + - getSettingsPath().toLocal8Bit().constData(), + getSettingsPath(), + QStringLiteral("path")); + QCommandLineOption settingsPathDeprecated( QStringLiteral("settingsPath")); + settingsPathDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(settingsPath); + parser.addOption(settingsPathDeprecated); - QCommandLineOption resourcePath(QStringList() << "resource-path" - << "resourcePath", + QCommandLineOption resourcePath(QStringLiteral("resource-path"), QCoreApplication::translate("CmdlineArgs", "Top-level directory where Mixxx should look for its " "resource files such as MIDI mappings, overriding the " "default installation location."), + QStringLiteral("path")); + QCommandLineOption resourcePathDeprecated( QStringLiteral("resourcePath")); + resourcePathDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(resourcePath); + parser.addOption(resourcePathDeprecated); - const QCommandLineOption timelinePath(QStringList() << "timeline-path" - << "timelinePath", - QCoreApplication::translate("CmdlineArgs", "Path the timeline is written to")); + const QCommandLineOption timelinePath(QStringLiteral("timeline-path"), + QCoreApplication::translate("CmdlineArgs", + "Path the debug statistics time line is written to"), + QStringLiteral("path")); + QCommandLineOption timelinePathDeprecated( + QStringLiteral("timelinePath"), timelinePath.description()); + timelinePathDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(timelinePath); + parser.addOption(timelinePathDeprecated); - const QCommandLineOption controllerDebug(QStringList() << "controller-debug" - << "controllerDebug" - << "midi-debug" - << "midiDebug", + const QCommandLineOption controllerDebug(QStringLiteral("controller-debug"), QCoreApplication::translate("CmdlineArgs", "Causes Mixxx to display/log all of the controller data it " "receives and script functions it loads")); + QCommandLineOption controllerDebugDeprecated( + QStringList({QStringLiteral("controllerDebug"), + QStringLiteral("midiDebug")})); + controllerDebugDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(controllerDebug); + parser.addOption(controllerDebugDeprecated); const QCommandLineOption developer(QStringLiteral("developer"), QCoreApplication::translate("CmdlineArgs", @@ -134,13 +151,15 @@ bool CmdlineArgs::parse(int argc, char** argv) { "performance, and a Developer tools menu.")); parser.addOption(developer); - const QCommandLineOption safeMode(QStringList() << "safe-mode" - << "safeMode", + const QCommandLineOption safeMode(QStringLiteral("safe-mode"), QCoreApplication::translate("CmdlineArgs", "Enables safe-mode. Disables OpenGL waveforms, and " "spinning vinyl widgets. Try this option if Mixxx is " "crashing on startup.")); + QCommandLineOption safeModeDeprecated(QStringLiteral("safeMode"), safeMode.description()); + safeModeDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(safeMode); + parser.addOption(safeModeDeprecated); const QCommandLineOption color(QStringLiteral("color"), QCoreApplication::translate("CmdlineArgs", @@ -149,8 +168,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { QStringLiteral("auto")); parser.addOption(color); - const QCommandLineOption logLevel(QStringList() << "log-level" - << "logLevel", + const QCommandLineOption logLevel(QStringLiteral("log-level"), QCoreApplication::translate("CmdlineArgs", "Sets the verbosity of command line logging.\n" "critical - Critical/Fatal only\n" @@ -158,26 +176,33 @@ bool CmdlineArgs::parse(int argc, char** argv) { "info - Above + Informational messages\n" "debug - Above + Debug/Developer messages\n" "trace - Above + Profiling messages"), - QStringLiteral("logLevel")); + QStringLiteral("level")); + QCommandLineOption logLevelDeprecated(QStringLiteral("logLevel"), logLevel.description()); + logLevelDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(logLevel); + parser.addOption(logLevelDeprecated); - const QCommandLineOption logFlushLevel(QStringList() << "log-flush-level" - << "logFlushLevel", + const QCommandLineOption logFlushLevel(QStringLiteral("log-flush-level"), QCoreApplication::translate("CmdlineArgs", "Sets the the logging level at which the log buffer is " - "flushed to mixxx.log. LEVEL is one of the values defined " - "at --logLevel above."), - QStringLiteral("logFlushLevel")); + "flushed to mixxx.log. is one of the values defined " + "at --log-level above."), + QStringLiteral("level")); + QCommandLineOption logFlushLevelDeprecated( + QStringLiteral("logFlushLevel"), logLevel.description()); + logFlushLevelDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(logFlushLevel); + parser.addOption(logFlushLevelDeprecated); -#ifdef MIXXX_BUILD_DEBUG - QCommandLineOption debugAssertBreak(QStringList() << "debug-assert-break" - << "debugAssertBreak", + QCommandLineOption debugAssertBreak(QStringLiteral("debug-assert-break"), QCoreApplication::translate("CmdlineArgs", "Breaks (SIGINT) Mixxx, if a DEBUG_ASSERT evaluates to " "false. Under a debugger you can continue afterwards.")); + QCommandLineOption debugAssertBreakDeprecated( + QStringLiteral("debugAssertBreak"), debugAssertBreak.description()); + debugAssertBreakDeprecated.setFlags(QCommandLineOption::HiddenFromHelp); parser.addOption(debugAssertBreak); -#endif + parser.addOption(debugAssertBreakDeprecated); const QCommandLineOption helpOption = parser.addHelpOption(); const QCommandLineOption versionOption = parser.addVersionOption(); @@ -208,7 +233,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { return false; } - m_startInFullscreen = parser.isSet(fullscreen); + m_startInFullscreen = parser.isSet(fullScreen); if (parser.isSet(locale)) { m_locale = parser.value(locale); @@ -220,23 +245,30 @@ bool CmdlineArgs::parse(int argc, char** argv) { m_settingsPath.append("/"); } m_settingsPathSet = true; + } else if (parser.isSet(settingsPathDeprecated)) { + m_settingsPath = parser.value(settingsPathDeprecated); + if (!m_settingsPath.endsWith("/")) { + m_settingsPath.append("/"); + } + m_settingsPathSet = true; } if (parser.isSet(resourcePath)) { m_resourcePath = parser.value(resourcePath); + } else if (parser.isSet(resourcePathDeprecated)) { + m_resourcePath = parser.value(resourcePathDeprecated); } if (parser.isSet(timelinePath)) { m_timelinePath = parser.value(timelinePath); + } else if (parser.isSet(timelinePathDeprecated)) { + m_timelinePath = parser.value(timelinePathDeprecated); } - m_midiDebug = parser.isSet(controllerDebug); + m_midiDebug = parser.isSet(controllerDebug) || parser.isSet(controllerDebugDeprecated); m_developer = parser.isSet(developer); - m_safeMode = parser.isSet(safeMode); - -#ifdef MIXXX_BUILD_DEBUG - m_debugAssertBreak = parser.isSet(debugAssertBreak); -#endif + m_safeMode = parser.isSet(safeMode) || parser.isSet(safeModeDeprecated); + m_debugAssertBreak = parser.isSet(debugAssertBreak) || parser.isSet(debugAssertBreakDeprecated); m_musicFiles = parser.positionalArguments(); @@ -246,6 +278,12 @@ bool CmdlineArgs::parse(int argc, char** argv) { "Mixxx will only print warnings and critical messages to the console.\n", stdout); } + } else if (parser.isSet(logLevelDeprecated)) { + if (!parseLogLevel(parser.value(logLevelDeprecated), &m_logLevel)) { + fputs("\nlogLevel wasn't 'trace', 'debug', 'info', 'warning', or 'critical'!\n" + "Mixxx will only print warnings and critical messages to the console.\n", + stdout); + } } else { if (m_developer) { m_logLevel = mixxx::LogLevel::Debug; @@ -258,6 +296,12 @@ bool CmdlineArgs::parse(int argc, char** argv) { "Mixxx will only flush output after a critical message.\n", stdout); } + } else if (parser.isSet(logFlushLevelDeprecated)) { + if (!parseLogLevel(parser.value(logFlushLevelDeprecated), &m_logFlushLevel)) { + fputs("\nlogFlushLevel wasn't 'trace', 'debug', 'info', 'warning', or 'critical'!\n" + "Mixxx will only flush output after a critical message.\n", + stdout); + } } // set colors @@ -281,7 +325,7 @@ bool CmdlineArgs::parse(int argc, char** argv) { } else if (parser.value(color).compare(QLatin1String("never"), Qt::CaseInsensitive) == 0) { m_useColors = false; } else { - qWarning() << "Unknown setting for color, ignoring"; + fputs("Unknown argument for for color.\n", stdout); } return true; From bdc852894a4d96fa7c66482c393197e4c1140ef1 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 29 Jun 2021 14:56:16 +0200 Subject: [PATCH 026/194] SidebarModel: Replace if-else ladder in data() with switch case --- src/library/sidebarmodel.cpp | 60 +++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/library/sidebarmodel.cpp b/src/library/sidebarmodel.cpp index 2dbd6c7ee63..40faccd2514 100644 --- a/src/library/sidebarmodel.cpp +++ b/src/library/sidebarmodel.cpp @@ -226,44 +226,48 @@ QVariant SidebarModel::data(const QModelIndex& index, int role) const { if (index.internalPointer() == this) { //If it points to SidebarModel - if (role == Qt::DisplayRole) { + switch (role) { + case Qt::DisplayRole: return m_sFeatures[index.row()]->title(); - } else if (role == Qt::DecorationRole) { + case Qt::DecorationRole: return m_sFeatures[index.row()]->icon(); - } else if (role == SidebarModel::IconNameRole) { + case SidebarModel::IconNameRole: return m_sFeatures[index.row()]->iconName(); + default: + return QVariant(); } - } - - if (index.internalPointer() != this) { + } else { // If it points to a TreeItem TreeItem* pTreeItem = static_cast(index.internalPointer()); - if (pTreeItem) { - if (role == Qt::DisplayRole) { + if (!pTreeItem) { + return QVariant(); + } + + switch (role) { + case Qt::DisplayRole: + return pTreeItem->getLabel(); + case Qt::ToolTipRole: { + // If it's the "Quick Links" node, display it's name + if (pTreeItem->getData().toString() == QUICK_LINK_NODE) { return pTreeItem->getLabel(); - } else if (role == Qt::ToolTipRole) { - // If it's the "Quick Links" node, display it's name - if (pTreeItem->getData().toString() == QUICK_LINK_NODE) { - return pTreeItem->getLabel(); - } else { - return pTreeItem->getData(); - } - } else if (role == Qt::FontRole) { - QFont font; - font.setBold(pTreeItem->isBold()); - return font; - } else if (role == Qt::DecorationRole) { - return pTreeItem->getIcon(); - } else if (role == SidebarModel::DataRole) { - return pTreeItem->getData(); - } else if (role == SidebarModel::IconNameRole) { - // TODO: Add support for icon names in tree items - return QString(); } + return pTreeItem->getData(); + } + case Qt::FontRole: { + QFont font; + font.setBold(pTreeItem->isBold()); + return font; + } + case Qt::DecorationRole: + return pTreeItem->getIcon(); + case SidebarModel::DataRole: + return pTreeItem->getData(); + case SidebarModel::IconNameRole: + // TODO: Add support for icon names in tree items + default: + return QVariant(); } } - - return QVariant(); } void SidebarModel::startPressedUntilClickedTimer(const QModelIndex& pressedIndex) { From 380c4575cb8a5f6e3089bf7f1a3d003d6d117620 Mon Sep 17 00:00:00 2001 From: luz paz Date: Tue, 29 Jun 2021 15:35:59 -0400 Subject: [PATCH 027/194] Fix misc. typos Found via `codespell -q 3 -S *.ts,*.po,*.rtf,./.git,./src/library,./lib,./build/wix -L ba,chang,crate,ect,everytime,german,hace,iff,jus,ith,lokal,nd,ons,pevent,pparent,preverse,seeked,sheat,sinc,splitted,substract,thru,tim,uint` --- .github/workflows/build.yml | 2 +- cmake/ctest-to-junit.xsl | 2 +- packaging/CPackDebInstall.cmake | 4 ++-- packaging/CPackDebUploadPPA.cmake | 2 +- packaging/macos/entitlements.plist | 2 +- res/controllers/Hercules_DJControl_Inpulse_200.midi.xml | 2 +- res/controllers/Hercules_DJControl_Jogvision.midi.xml | 2 +- res/controllers/Numark-N4-scripts.js | 2 +- res/controllers/Pioneer-DDJ-200-scripts.js | 2 +- res/controllers/Pioneer-DDJ-400.midi.xml | 8 ++++---- res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js | 2 +- res/skins/LateNight/fx/unit_parameters_hidden.xml | 2 +- res/skins/LateNight/skin.xml | 6 +++--- res/skins/LateNight/style.qss | 2 +- res/skins/LateNight/style_palemoon.qss | 4 ++-- res/skins/default-menu-styles-linux.qss | 2 +- res/skins/default-menu-styles-windows.qss | 2 +- res/skins/default.qss | 2 +- src/controllers/hid/hidcontroller.cpp | 4 ++-- src/encoder/encoderfdkaac.cpp | 2 +- src/engine/controls/clockcontrol.cpp | 4 ++-- src/engine/enginemaster.cpp | 2 +- src/mixxx.cpp | 2 +- src/mixxx.rc | 2 +- src/sources/audiosource.h | 2 +- src/sources/soundsourcecoreaudio.cpp | 2 +- src/sources/soundsourcem4a.cpp | 2 +- src/test/beatgridtest.cpp | 8 ++++---- src/test/beatmaptest.cpp | 6 +++--- src/test/enginesynctest.cpp | 2 +- src/track/beatutils.cpp | 2 +- src/track/serato/markers2.h | 4 ++-- src/track/track.cpp | 4 ++-- src/track/trackrecord.h | 2 +- src/util/db/sqlite.cpp | 2 +- src/util/fileinfo.h | 4 ++-- src/util/qt.h | 2 +- src/util/sample.cpp | 2 +- src/waveform/renderers/waveformmark.h | 2 +- src/waveform/renderers/waveformrendermark.cpp | 4 ++-- src/widget/wpushbutton.cpp | 4 ++-- tools/debian_buildenv.sh | 4 ++-- tools/deploy.py | 2 +- tools/githelper.py | 2 +- tools/macos_buildenv.sh | 4 ++-- tools/unzip.ps1 | 2 +- 46 files changed, 67 insertions(+), 67 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2517a25337a..4859244de7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -160,7 +160,7 @@ jobs: # Studio on Windows comes with its own CMake version anyway. if: runner.os == 'macOS' with: - # This should always match the mininum required version in + # This should always match the minimum required version in # our CMakeLists.txt cmake-version: '3.16.x' diff --git a/cmake/ctest-to-junit.xsl b/cmake/ctest-to-junit.xsl index 8bd53978b6a..ad4869944f0 100644 --- a/cmake/ctest-to-junit.xsl +++ b/cmake/ctest-to-junit.xsl @@ -4,7 +4,7 @@ This XSLT stylesheet is taken from the jenkins-ctest-plugin by Version One, Inc. and Ryan Pavlik and is subject to the terms of the MIT License. -It was taken from this GitHub repositiory: +It was taken from this GitHub repository: https://github.com/rpavlik/jenkins-ctest-plugin Includes modifications by Jan Holthuis to add support for skipped/errored diff --git a/packaging/CPackDebInstall.cmake b/packaging/CPackDebInstall.cmake index 16e99ecb72d..a3198e1dd51 100644 --- a/packaging/CPackDebInstall.cmake +++ b/packaging/CPackDebInstall.cmake @@ -23,7 +23,7 @@ if(NOT CPACK_DEBIAN_DEBCHANGE) endif() # We create a temporary debian folder that the debhelper below run as usual. -# The final debian folder is created indipendently by cpack +# The final debian folder is created independently by cpack message( NOTICE "Creating temporary debian folder for debhelper" ) file(COPY ${CPACK_DEBIAN_SOURCE_DIR}/packaging/debian DESTINATION ${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}) @@ -69,7 +69,7 @@ function(run_dh DH_COMMAND) WORKING_DIRECTORY ${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME} RESULT_VARIABLE CPACK_DEBIAN_DH_RET) if(NOT CPACK_DEBIAN_DH_RET EQUAL "0") - message(FATAL_ERROR "${DH_COMMAND} retuned exit code ${CPACK_DEBIAN_DH_RET}") + message(FATAL_ERROR "${DH_COMMAND} returned exit code ${CPACK_DEBIAN_DH_RET}") endif() endfunction() diff --git a/packaging/CPackDebUploadPPA.cmake b/packaging/CPackDebUploadPPA.cmake index daaa59a8126..23eb1e53ede 100644 --- a/packaging/CPackDebUploadPPA.cmake +++ b/packaging/CPackDebUploadPPA.cmake @@ -117,7 +117,7 @@ foreach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES}) WORKING_DIRECTORY ${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME} RESULT_VARIABLE CPACK_DEBIAN_DEBUILD_RET) if(NOT CPACK_DEBIAN_DEBUILD_RET EQUAL "0") - message(FATAL_ERROR "${CPACK_DEBIAN_DEBUILD} retuned exit code ${CPACK_DEBIAN_DEBUILD_RET}") + message(FATAL_ERROR "${CPACK_DEBIAN_DEBUILD} returned exit code ${CPACK_DEBIAN_DEBUILD_RET}") endif() endif() if (BUILD_MACHINE_RELEASE STREQUAL RELEASE AND DEB_BUILD) diff --git a/packaging/macos/entitlements.plist b/packaging/macos/entitlements.plist index 126ccd7564d..7193269b745 100644 --- a/packaging/macos/entitlements.plist +++ b/packaging/macos/entitlements.plist @@ -30,7 +30,7 @@ com.apple.security.files.user-selected.read-write - + com.apple.security.files.bookmarks.app-scope diff --git a/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml b/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml index 1b87f171e74..d9d36d6b143 100644 --- a/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml +++ b/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml @@ -1303,7 +1303,7 @@ 0x07 0x05 - + [AutoDJ] enabled diff --git a/res/controllers/Hercules_DJControl_Jogvision.midi.xml b/res/controllers/Hercules_DJControl_Jogvision.midi.xml index aeb87ae3216..d7723cd3b5a 100644 --- a/res/controllers/Hercules_DJControl_Jogvision.midi.xml +++ b/res/controllers/Hercules_DJControl_Jogvision.midi.xml @@ -1721,7 +1721,7 @@ [Master] maximize_library - VIEW buton LED + VIEW button LED 0.5 1 0x90 diff --git a/res/controllers/Numark-N4-scripts.js b/res/controllers/Numark-N4-scripts.js index fcf8a427f6f..9967cbf3038 100644 --- a/res/controllers/Numark-N4-scripts.js +++ b/res/controllers/Numark-N4-scripts.js @@ -24,7 +24,7 @@ NumarkN4.cueReverseRoll=true; // enables the ability to do a reverse roll while NumarkN4.hotcuePageIndexBehavior=true; // possible ranges (0.0..3.0 where 0.06=6%) -NumarkN4.rateRanges = [0, // default (gets set via script later; don't modifify) +NumarkN4.rateRanges = [0, // default (gets set via script later; don't modify) 0.06, // one semitone 0.24, // for maximum freedom ]; diff --git a/res/controllers/Pioneer-DDJ-200-scripts.js b/res/controllers/Pioneer-DDJ-200-scripts.js index 5cfc7274597..e1f03a234a2 100644 --- a/res/controllers/Pioneer-DDJ-200-scripts.js +++ b/res/controllers/Pioneer-DDJ-200-scripts.js @@ -31,7 +31,7 @@ DDJ200.init = function() { DDJ200.switchPlayLED(d, ch); }); - // run switchSyncLED after sync toogle to set LEDs accordingly + // run switchSyncLED after sync toggle to set LEDs accordingly engine.makeConnection(vgroup, "sync_enabled", function(ch, vgroup) { var vDeckNo = script.deckFromGroup(vgroup); var d = (vDeckNo % 2) ? 0 : 1; diff --git a/res/controllers/Pioneer-DDJ-400.midi.xml b/res/controllers/Pioneer-DDJ-400.midi.xml index a2cc1d28eba..d1abe4e38b1 100644 --- a/res/controllers/Pioneer-DDJ-400.midi.xml +++ b/res/controllers/Pioneer-DDJ-400.midi.xml @@ -206,7 +206,7 @@ - JOG DIAL PLATTER (DECK1) - touch - enabe (on touch) / disable (on release) Scraching/Pitch + JOG DIAL PLATTER (DECK1) - touch - enable (on touch) / disable (on release) Scratching/Pitch bend [Channel1] @@ -218,7 +218,7 @@ - JOG DIAL PLATTER +SHIFT (DECK1) - touch - enabe (on touch) / disable (on release) highspeed + JOG DIAL PLATTER +SHIFT (DECK1) - touch - enable (on touch) / disable (on release) highspeed Pitch bend [Channel1] @@ -271,7 +271,7 @@ - JOG DIAL PLATTER (DECK2) - touch - enabe (on touch) / disable (on release) Scraching/Pitch + JOG DIAL PLATTER (DECK2) - touch - enable (on touch) / disable (on release) Scratching/Pitch bend [Channel2] @@ -283,7 +283,7 @@ - JOG DIAL PLATTER +SHIFT (DECK2) - touch - enabe (on touch) / disable (on release) highspeed + JOG DIAL PLATTER +SHIFT (DECK2) - touch - enable (on touch) / disable (on release) highspeed Pitch bend [Channel2] diff --git a/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js index c98765289da..6507bf3548e 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js @@ -187,7 +187,7 @@ TraktorS2MK3.registerInputPackets = function () { this.registerInputScaler(messageLong, "[Master]", "crossfader", 0x05, 0xFFFF, this.parameterHandler); /* do NOT map the "master" button because it also drives the analog output gain. - Disabling this mapping is the only way to have independant controls for the + Disabling this mapping is the only way to have independent controls for the digital master gain and the output level - the latter usually needs to be set at 100%. */ diff --git a/res/skins/LateNight/fx/unit_parameters_hidden.xml b/res/skins/LateNight/fx/unit_parameters_hidden.xml index dc92a339730..9fe21ee27b8 100644 --- a/res/skins/LateNight/fx/unit_parameters_hidden.xml +++ b/res/skins/LateNight/fx/unit_parameters_hidden.xml @@ -18,7 +18,7 @@ horizontal - + + When a track is loaded the bg gets darker for better contrast --> #19191a #001b23 rgba(15, 15, 15, 20) @@ -249,7 +249,7 @@ blue white 0f,0f @@ -392,7 +392,7 @@