-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2899 from uklotzde/wtrackmenu_batchprocessing
WTrackMenu: Display a modal progress dialog
- Loading branch information
Showing
16 changed files
with
1,280 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#include "library/trackcollectioniterator.h" | ||
|
||
#include "library/trackcollection.h" | ||
|
||
namespace mixxx { | ||
|
||
std::optional<TrackPointer> TrackByIdCollectionIterator::nextItem() { | ||
const auto nextTrackId = | ||
m_trackIdListIter.nextItem(); | ||
if (!nextTrackId) { | ||
return std::nullopt; | ||
} | ||
const auto trackPtr = | ||
m_pTrackCollection->getTrackById(*nextTrackId); | ||
if (!trackPtr) { | ||
return std::nullopt; | ||
} | ||
return std::make_optional(trackPtr); | ||
} | ||
|
||
} // namespace mixxx |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/// Utilities for iterating through a selection or collection | ||
/// of tracks. | ||
|
||
#pragma once | ||
|
||
#include <QModelIndex> | ||
|
||
#include "track/trackiterator.h" | ||
|
||
class TrackCollection; | ||
|
||
namespace mixxx { | ||
|
||
/// Iterate over selected and valid(!) track pointers in a TrackModel. | ||
/// Invalid (= nullptr) track pointers are skipped silently. | ||
class TrackByIdCollectionIterator final | ||
: public virtual TrackPointerIterator { | ||
public: | ||
TrackByIdCollectionIterator( | ||
const TrackCollection* pTrackCollection, | ||
const TrackIdList& trackIds) | ||
: m_pTrackCollection(pTrackCollection), | ||
m_trackIdListIter(trackIds) { | ||
DEBUG_ASSERT(m_pTrackCollection); | ||
} | ||
~TrackByIdCollectionIterator() override = default; | ||
|
||
void reset() override { | ||
m_trackIdListIter.reset(); | ||
} | ||
|
||
std::optional<int> estimateItemsRemaining() override { | ||
return m_trackIdListIter.estimateItemsRemaining(); | ||
} | ||
|
||
std::optional<TrackPointer> nextItem() override; | ||
|
||
private: | ||
const TrackCollection* const m_pTrackCollection; | ||
TrackIdListIterator m_trackIdListIter; | ||
}; | ||
|
||
} // namespace mixxx |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#include "library/trackmodeliterator.h" | ||
|
||
#include "library/trackmodel.h" | ||
|
||
namespace mixxx { | ||
|
||
std::optional<TrackId> TrackIdModelIterator::nextItem() { | ||
const auto nextModelIndex = | ||
m_modelIndexListIter.nextItem(); | ||
if (!nextModelIndex) { | ||
return std::nullopt; | ||
} | ||
const auto trackId = | ||
m_pTrackModel->getTrackId(*nextModelIndex); | ||
if (!trackId.isValid()) { | ||
return std::nullopt; | ||
} | ||
return std::make_optional(trackId); | ||
} | ||
|
||
std::optional<TrackPointer> TrackPointerModelIterator::nextItem() { | ||
const auto nextModelIndex = | ||
m_modelIndexListIter.nextItem(); | ||
if (!nextModelIndex) { | ||
return std::nullopt; | ||
} | ||
const auto trackPtr = | ||
m_pTrackModel->getTrack(*nextModelIndex); | ||
if (!trackPtr) { | ||
return std::nullopt; | ||
} | ||
return std::make_optional(trackPtr); | ||
} | ||
|
||
} // namespace mixxx |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/// Utilities for iterating through a selection or collection | ||
/// of tracks identified by QModelIndex. | ||
|
||
#pragma once | ||
|
||
#include <QModelIndex> | ||
|
||
#include "track/trackiterator.h" | ||
|
||
class TrackModel; | ||
|
||
namespace mixxx { | ||
|
||
/// Iterate over selected, valid track ids in a TrackModel. | ||
/// Invalid track ids are skipped silently. | ||
class TrackIdModelIterator final | ||
: public virtual TrackIdIterator { | ||
public: | ||
TrackIdModelIterator( | ||
const TrackModel* pTrackModel, | ||
const QModelIndexList& indexList) | ||
: m_pTrackModel(pTrackModel), | ||
m_modelIndexListIter(indexList) { | ||
DEBUG_ASSERT(m_pTrackModel); | ||
} | ||
~TrackIdModelIterator() override = default; | ||
|
||
void reset() override { | ||
m_modelIndexListIter.reset(); | ||
} | ||
|
||
std::optional<int> estimateItemsRemaining() override { | ||
return m_modelIndexListIter.estimateItemsRemaining(); | ||
} | ||
|
||
std::optional<TrackId> nextItem() override; | ||
|
||
private: | ||
const TrackModel* const m_pTrackModel; | ||
ListItemIterator<QModelIndex> m_modelIndexListIter; | ||
}; | ||
|
||
/// Iterate over selected, valid track pointers in a TrackModel. | ||
/// Invalid (= nullptr) track pointers are skipped silently. | ||
class TrackPointerModelIterator final | ||
: public virtual TrackPointerIterator { | ||
public: | ||
TrackPointerModelIterator( | ||
const TrackModel* pTrackModel, | ||
const QModelIndexList& indexList) | ||
: m_pTrackModel(pTrackModel), | ||
m_modelIndexListIter(indexList) { | ||
DEBUG_ASSERT(m_pTrackModel); | ||
} | ||
~TrackPointerModelIterator() override = default; | ||
|
||
void reset() override { | ||
m_modelIndexListIter.reset(); | ||
} | ||
|
||
std::optional<int> estimateItemsRemaining() override { | ||
return m_modelIndexListIter.estimateItemsRemaining(); | ||
} | ||
|
||
std::optional<TrackPointer> nextItem() override; | ||
|
||
private: | ||
const TrackModel* const m_pTrackModel; | ||
ListItemIterator<QModelIndex> m_modelIndexListIter; | ||
}; | ||
|
||
} // namespace mixxx |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#include "library/trackprocessing.h" | ||
|
||
#include <QThread> | ||
|
||
#include "library/trackcollection.h" | ||
#include "library/trackcollectionmanager.h" | ||
#include "util/logger.h" | ||
|
||
namespace mixxx { | ||
|
||
namespace { | ||
|
||
const Logger kLogger("ModalTrackBatchProcessor"); | ||
|
||
} // anonymous namespace | ||
|
||
int ModalTrackBatchProcessor::processTracks( | ||
const QString& progressLabelText, | ||
TrackCollectionManager* pTrackCollectionManager, | ||
TrackPointerIterator* pTrackPointerIterator) { | ||
DEBUG_ASSERT(pTrackCollectionManager); | ||
DEBUG_ASSERT(pTrackPointerIterator); | ||
DEBUG_ASSERT(QThread::currentThread() == | ||
pTrackCollectionManager->thread()); | ||
int finishedTrackCount = 0; | ||
// The total count is initialized with the remaining count | ||
// before starting the iteration. If this value is unknown | ||
// we use 0 as the default until an estimation is available | ||
// (see update below). | ||
int estimatedTotalCount = | ||
pTrackPointerIterator->estimateItemsRemaining().value_or(0); | ||
m_bAborted = false; | ||
TaskMonitor taskMonitor( | ||
progressLabelText, | ||
m_minimumProgressDuration, | ||
this); | ||
taskMonitor.registerTask(this); | ||
while (auto nextTrackPointer = pTrackPointerIterator->nextItem()) { | ||
const auto pTrack = *nextTrackPointer; | ||
VERIFY_OR_DEBUG_ASSERT(pTrack) { | ||
kLogger.warning() | ||
<< progressLabelText | ||
<< "failed to load next track for processing"; | ||
continue; | ||
} | ||
if (m_bAborted) { | ||
kLogger.info() | ||
<< "Aborting" | ||
<< progressLabelText | ||
<< "after processing" | ||
<< finishedTrackCount | ||
<< "of" | ||
<< estimatedTotalCount | ||
<< "track(s)"; | ||
return finishedTrackCount; | ||
} | ||
switch (doProcessNextTrack(pTrack)) { | ||
case ProcessNextTrackResult::AbortProcessing: | ||
kLogger.info() | ||
<< progressLabelText | ||
<< "aborted while processing" | ||
<< finishedTrackCount + 1 | ||
<< "of" | ||
<< estimatedTotalCount | ||
<< "track(s)"; | ||
return finishedTrackCount; | ||
case ProcessNextTrackResult::ContinueProcessing: | ||
break; | ||
case ProcessNextTrackResult::SaveTrackAndContinueProcessing: | ||
pTrackCollectionManager->saveTrack(pTrack); | ||
break; | ||
} | ||
++finishedTrackCount; | ||
if (finishedTrackCount > estimatedTotalCount) { | ||
// Update the total count which cannot be less than the | ||
// number of already finished items plus the estimated number | ||
// of remaining items. | ||
auto estimatedRemainingCount = | ||
pTrackPointerIterator->estimateItemsRemaining().value_or(0); | ||
estimatedTotalCount = finishedTrackCount + estimatedRemainingCount; | ||
} | ||
DEBUG_ASSERT(finishedTrackCount <= estimatedTotalCount); | ||
taskMonitor.reportTaskProgress( | ||
this, | ||
kPercentageOfCompletionMin + | ||
(kPercentageOfCompletionMax - | ||
kPercentageOfCompletionMin) * | ||
finishedTrackCount / | ||
static_cast<PercentageOfCompletion>( | ||
estimatedTotalCount)); | ||
} | ||
return finishedTrackCount; | ||
} | ||
|
||
ModalTrackBatchOperationProcessor::ModalTrackBatchOperationProcessor( | ||
const TrackPointerOperation* pTrackPointerOperation, | ||
Mode mode, | ||
Duration progressGracePeriod, | ||
QObject* parent) | ||
: ModalTrackBatchProcessor(progressGracePeriod, parent), | ||
m_pTrackPointerOperation(pTrackPointerOperation), | ||
m_mode(mode) { | ||
DEBUG_ASSERT(m_pTrackPointerOperation); | ||
} | ||
|
||
ModalTrackBatchProcessor::ProcessNextTrackResult | ||
ModalTrackBatchOperationProcessor::doProcessNextTrack( | ||
const TrackPointer& pTrack) { | ||
m_pTrackPointerOperation->apply(pTrack); | ||
switch (m_mode) { | ||
case Mode::Apply: | ||
return ProcessNextTrackResult::ContinueProcessing; | ||
case Mode::ApplyAndSave: | ||
return ProcessNextTrackResult::SaveTrackAndContinueProcessing; | ||
} | ||
DEBUG_ASSERT(!"unreachable"); | ||
return ProcessNextTrackResult::AbortProcessing; | ||
} | ||
|
||
} // namespace mixxx |
Oops, something went wrong.