Browse Source

Merge pull request #12035 from glassez/move-storage

Move torrent storages one by one
adaptive-webui-19844
Vladimir Golovnev 5 years ago committed by GitHub
parent
commit
5127156ba4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 116
      src/base/bittorrent/session.cpp
  2. 18
      src/base/bittorrent/session.h
  3. 220
      src/base/bittorrent/torrenthandle.cpp
  4. 26
      src/base/bittorrent/torrenthandle.h
  5. 3
      src/gui/transferlistwidget.cpp

116
src/base/bittorrent/session.cpp

@ -1815,8 +1815,19 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio
for (const QString &file : files) for (const QString &file : files)
Utils::Fs::forceRemove(resumeDataDir.absoluteFilePath(file)); Utils::Fs::forceRemove(resumeDataDir.absoluteFilePath(file));
if (m_moveStorageQueue.size() > 1) {
// Delete "move storage job" for the deleted torrent
// (note: we shouldn't delete active job)
const auto iter = std::find_if(m_moveStorageQueue.begin() + 1, m_moveStorageQueue.end()
, [torrent](const MoveStorageJob &job)
{
return job.torrent == torrent;
});
if (iter != m_moveStorageQueue.end())
m_moveStorageQueue.erase(iter);
}
delete torrent; delete torrent;
qDebug("Torrent deleted.");
return true; return true;
} }
@ -3938,6 +3949,78 @@ void Session::handleTorrentTrackerError(TorrentHandle *const torrent, const QStr
emit trackerError(torrent, trackerUrl); emit trackerError(torrent, trackerUrl);
} }
bool Session::addMoveTorrentStorageJob(TorrentHandle *torrent, const QString &newPath, const MoveStorageMode mode)
{
Q_ASSERT(torrent);
if (m_moveStorageQueue.size() > 1) {
const auto iter = std::find_if(m_moveStorageQueue.begin() + 1, m_moveStorageQueue.end()
, [torrent](const MoveStorageJob &job)
{
return job.torrent == torrent;
});
if (iter != m_moveStorageQueue.end()) {
// remove existing inactive job
m_moveStorageQueue.erase(iter);
}
}
QString currentLocation = QString::fromStdString(
torrent->nativeHandle().status(lt::torrent_handle::query_save_path).save_path);
if (!m_moveStorageQueue.isEmpty() && (m_moveStorageQueue.first().torrent == torrent)) {
// if there is active job for this torrent consider its target path as current location
// of this torrent to prevent creating meaningless job that will do nothing
currentLocation = m_moveStorageQueue.first().path;
}
if (QDir {currentLocation} == QDir {newPath})
return false;
const MoveStorageJob moveStorageJob {torrent, newPath, mode};
qDebug("Move storage from \"%s\" to \"%s\" is enqueued.", qUtf8Printable(currentLocation), qUtf8Printable(newPath));
if (m_moveStorageQueue.size() == 1)
moveTorrentStorage(moveStorageJob);
return true;
}
void Session::moveTorrentStorage(const MoveStorageJob &job) const
{
lt::torrent_handle handle = job.torrent->nativeHandle();
qDebug("Moving torrent storage to \"%s\"...", qUtf8Printable(job.path));
#if (LIBTORRENT_VERSION_NUM < 10200)
handle.move_storage(job.path.toUtf8().constData()
, ((job.mode == MoveStorageMode::Overwrite)
? lt::always_replace_files : lt::dont_replace));
#else
handle.move_storage(job.path.toUtf8().constData()
, ((job.mode == MoveStorageMode::Overwrite)
? lt::move_flags_t::always_replace_files : lt::move_flags_t::dont_replace));
#endif
}
void Session::handleMoveTorrentStorageJobFinished(const QString &errorMessage)
{
Q_ASSERT(!m_moveStorageQueue.isEmpty());
const MoveStorageJob finishedJob = m_moveStorageQueue.takeFirst();
if (!m_moveStorageQueue.isEmpty())
moveTorrentStorage(m_moveStorageQueue.first());
const auto iter = std::find_if(m_moveStorageQueue.cbegin(), m_moveStorageQueue.cend()
, [&finishedJob](const MoveStorageJob &job)
{
return job.torrent == finishedJob.torrent;
});
if (iter == m_moveStorageQueue.cend()) {
// There is no more job for this torrent
finishedJob.torrent->handleStorageMoved(finishedJob.path, errorMessage);
}
}
void Session::handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl) void Session::handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl)
{ {
emit trackerWarning(torrent, trackerUrl); emit trackerWarning(torrent, trackerUrl);
@ -4254,8 +4337,6 @@ void Session::handleAlert(const lt::alert *a)
case lt::torrent_finished_alert::alert_type: case lt::torrent_finished_alert::alert_type:
case lt::save_resume_data_alert::alert_type: case lt::save_resume_data_alert::alert_type:
case lt::save_resume_data_failed_alert::alert_type: case lt::save_resume_data_failed_alert::alert_type:
case lt::storage_moved_alert::alert_type:
case lt::storage_moved_failed_alert::alert_type:
case lt::torrent_paused_alert::alert_type: case lt::torrent_paused_alert::alert_type:
case lt::torrent_resumed_alert::alert_type: case lt::torrent_resumed_alert::alert_type:
case lt::tracker_error_alert::alert_type: case lt::tracker_error_alert::alert_type:
@ -4319,6 +4400,12 @@ void Session::handleAlert(const lt::alert *a)
handleAlertsDroppedAlert(static_cast<const lt::alerts_dropped_alert *>(a)); handleAlertsDroppedAlert(static_cast<const lt::alerts_dropped_alert *>(a));
break; break;
#endif #endif
case lt::storage_moved_alert::alert_type:
handleStorageMovedAlert(static_cast<const lt::storage_moved_alert*>(a));
break;
case lt::storage_moved_failed_alert::alert_type:
handleStorageMovedFailedAlert(static_cast<const lt::storage_moved_failed_alert*>(a));
break;
} }
} }
catch (const std::exception &exc) { catch (const std::exception &exc) {
@ -4813,6 +4900,29 @@ void Session::handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const
} }
#endif #endif
void Session::handleStorageMovedAlert(const lt::storage_moved_alert *p)
{
if (m_moveStorageQueue.isEmpty()) return;
const TorrentHandle *torrent = m_torrents.value(p->handle.info_hash());
const MoveStorageJob &currentJob = m_moveStorageQueue.first();
if (currentJob.torrent != torrent) return;
const QString newPath {p->storage_path()};
handleMoveTorrentStorageJobFinished(newPath != currentJob.path ? tr("New path doesn't match a target path.") : QString {});
}
void Session::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p)
{
if (m_moveStorageQueue.isEmpty()) return;
const TorrentHandle *torrent = m_torrents.value(p->handle.info_hash());
const MoveStorageJob &currentJob = m_moveStorageQueue.first();
if (currentJob.torrent != torrent) return;
handleMoveTorrentStorageJobFinished(QString::fromStdString(p->message()));
}
void Session::handleStateUpdateAlert(const lt::state_update_alert *p) void Session::handleStateUpdateAlert(const lt::state_update_alert *p)
{ {
QVector<BitTorrent::TorrentHandle *> updatedTorrents; QVector<BitTorrent::TorrentHandle *> updatedTorrents;

18
src/base/bittorrent/session.h

@ -96,6 +96,8 @@ namespace BitTorrent
class TrackerEntry; class TrackerEntry;
struct CreateTorrentParams; struct CreateTorrentParams;
enum class MoveStorageMode;
// Using `Q_ENUM_NS()` without a wrapper namespace in our case is not advised // Using `Q_ENUM_NS()` without a wrapper namespace in our case is not advised
// since `Q_NAMESPACE` cannot be used when the same namespace resides at different files. // since `Q_NAMESPACE` cannot be used when the same namespace resides at different files.
// https://www.kdab.com/new-qt-5-8-meta-object-support-namespaces/#comment-143779 // https://www.kdab.com/new-qt-5-8-meta-object-support-namespaces/#comment-143779
@ -461,6 +463,8 @@ namespace BitTorrent
void handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl); void handleTorrentTrackerWarning(TorrentHandle *const torrent, const QString &trackerUrl);
void handleTorrentTrackerError(TorrentHandle *const torrent, const QString &trackerUrl); void handleTorrentTrackerError(TorrentHandle *const torrent, const QString &trackerUrl);
bool addMoveTorrentStorageJob(TorrentHandle *torrent, const QString &newPath, MoveStorageMode mode);
signals: signals:
void addTorrentFailed(const QString &error); void addTorrentFailed(const QString &error);
void allTorrentsFinished(); void allTorrentsFinished();
@ -514,6 +518,13 @@ namespace BitTorrent
void networkConfigurationChange(const QNetworkConfiguration &); void networkConfigurationChange(const QNetworkConfiguration &);
private: private:
struct MoveStorageJob
{
TorrentHandle *torrent;
QString path;
MoveStorageMode mode;
};
struct RemovingTorrentData struct RemovingTorrentData
{ {
QString name; QString name;
@ -583,6 +594,8 @@ namespace BitTorrent
#if (LIBTORRENT_VERSION_NUM >= 10200) #if (LIBTORRENT_VERSION_NUM >= 10200)
void handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const; void handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const;
#endif #endif
void handleStorageMovedAlert(const lt::storage_moved_alert *p);
void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p);
void createTorrentHandle(const lt::torrent_handle &nativeHandle); void createTorrentHandle(const lt::torrent_handle &nativeHandle);
@ -592,6 +605,9 @@ namespace BitTorrent
std::vector<lt::alert *> getPendingAlerts(lt::time_duration time = lt::time_duration::zero()) const; std::vector<lt::alert *> getPendingAlerts(lt::time_duration time = lt::time_duration::zero()) const;
void moveTorrentStorage(const MoveStorageJob &job) const;
void handleMoveTorrentStorageJobFinished(const QString &errorMessage = {});
// BitTorrent // BitTorrent
lt::session *m_nativeSession = nullptr; lt::session *m_nativeSession = nullptr;
@ -732,6 +748,8 @@ namespace BitTorrent
QNetworkConfigurationManager *m_networkManager = nullptr; QNetworkConfigurationManager *m_networkManager = nullptr;
QList<MoveStorageJob> m_moveStorageQueue;
static Session *m_instance; static Session *m_instance;
}; };
} }

220
src/base/bittorrent/torrenthandle.cpp

@ -327,7 +327,7 @@ QString TorrentHandle::currentTracker() const
QString TorrentHandle::savePath(bool actual) const QString TorrentHandle::savePath(bool actual) const
{ {
if (actual) if (actual)
return Utils::Fs::toUniformPath(nativeActualSavePath()); return Utils::Fs::toUniformPath(actualStorageLocation());
else else
return Utils::Fs::toUniformPath(m_savePath); return Utils::Fs::toUniformPath(m_savePath);
} }
@ -369,7 +369,7 @@ void TorrentHandle::setAutoTMMEnabled(bool enabled)
m_session->handleTorrentSavingModeChanged(this); m_session->handleTorrentSavingModeChanged(this);
if (m_useAutoTMM) if (m_useAutoTMM)
move_impl(m_session->categorySavePath(m_category), true); move_impl(m_session->categorySavePath(m_category), MoveStorageMode::Overwrite);
} }
bool TorrentHandle::hasRootFolder() const bool TorrentHandle::hasRootFolder() const
@ -377,7 +377,7 @@ bool TorrentHandle::hasRootFolder() const
return m_hasRootFolder; return m_hasRootFolder;
} }
QString TorrentHandle::nativeActualSavePath() const QString TorrentHandle::actualStorageLocation() const
{ {
return QString::fromStdString(m_nativeStatus.save_path); return QString::fromStdString(m_nativeStatus.save_path);
} }
@ -898,44 +898,42 @@ void TorrentHandle::updateState()
else if (isMoveInProgress()) { else if (isMoveInProgress()) {
m_state = TorrentState::Moving; m_state = TorrentState::Moving;
} }
else if (hasMissingFiles()) {
m_state = TorrentState::MissingFiles;
}
else if (isPaused()) { else if (isPaused()) {
if (hasMissingFiles()) m_state = isSeed() ? TorrentState::PausedUploading : TorrentState::PausedDownloading;
m_state = TorrentState::MissingFiles; }
else else if (m_session->isQueueingSystemEnabled() && isQueued() && !isChecking()) {
m_state = isSeed() ? TorrentState::PausedUploading : TorrentState::PausedDownloading; m_state = isSeed() ? TorrentState::QueuedUploading : TorrentState::QueuedDownloading;
} }
else { else {
if (m_session->isQueueingSystemEnabled() && isQueued() && !isChecking()) { switch (m_nativeStatus.state) {
m_state = isSeed() ? TorrentState::QueuedUploading : TorrentState::QueuedDownloading; case lt::torrent_status::finished:
} case lt::torrent_status::seeding:
else { if (isForced())
switch (m_nativeStatus.state) { m_state = TorrentState::ForcedUploading;
case lt::torrent_status::finished: else
case lt::torrent_status::seeding: m_state = m_nativeStatus.upload_payload_rate > 0 ? TorrentState::Uploading : TorrentState::StalledUploading;
if (isForced()) break;
m_state = TorrentState::ForcedUploading; case lt::torrent_status::allocating:
else m_state = TorrentState::Allocating;
m_state = m_nativeStatus.upload_payload_rate > 0 ? TorrentState::Uploading : TorrentState::StalledUploading; break;
break; case lt::torrent_status::checking_files:
case lt::torrent_status::allocating: m_state = m_hasSeedStatus ? TorrentState::CheckingUploading : TorrentState::CheckingDownloading;
m_state = TorrentState::Allocating; break;
break; case lt::torrent_status::downloading_metadata:
case lt::torrent_status::checking_files: m_state = TorrentState::DownloadingMetadata;
m_state = m_hasSeedStatus ? TorrentState::CheckingUploading : TorrentState::CheckingDownloading; break;
break; case lt::torrent_status::downloading:
case lt::torrent_status::downloading_metadata: if (isForced())
m_state = TorrentState::DownloadingMetadata; m_state = TorrentState::ForcedDownloading;
break; else
case lt::torrent_status::downloading: m_state = m_nativeStatus.download_payload_rate > 0 ? TorrentState::Downloading : TorrentState::StalledDownloading;
if (isForced()) break;
m_state = TorrentState::ForcedDownloading; default:
else qWarning("Unrecognized torrent status, should not happen!!! status was %d", m_nativeStatus.state);
m_state = m_nativeStatus.download_payload_rate > 0 ? TorrentState::Downloading : TorrentState::StalledDownloading; m_state = TorrentState::Unknown;
break;
default:
qWarning("Unrecognized torrent status, should not happen!!! status was %d", m_nativeStatus.state);
m_state = TorrentState::Unknown;
}
} }
} }
} }
@ -1334,7 +1332,7 @@ bool TorrentHandle::setCategory(const QString &category)
if (m_useAutoTMM) { if (m_useAutoTMM) {
if (!m_session->isDisableAutoTMMWhenCategoryChanged()) if (!m_session->isDisableAutoTMMWhenCategoryChanged())
move_impl(m_session->categorySavePath(m_category), true); move_impl(m_session->categorySavePath(m_category), MoveStorageMode::Overwrite);
else else
setAutoTMMEnabled(false); setAutoTMMEnabled(false);
} }
@ -1354,21 +1352,19 @@ void TorrentHandle::move(QString path)
if (!path.endsWith('/')) if (!path.endsWith('/'))
path += '/'; path += '/';
move_impl(path, false); move_impl(path, MoveStorageMode::KeepExistingFiles);
} }
void TorrentHandle::move_impl(QString path, bool overwrite) void TorrentHandle::move_impl(QString path, const MoveStorageMode mode)
{ {
if (path == savePath()) return; if (path == savePath()) return;
path = Utils::Fs::toNativePath(path); path = Utils::Fs::toNativePath(path);
if (!useTempPath()) { if (!useTempPath())
moveStorage(path, overwrite); moveStorage(path, mode);
}
else { m_savePath = path;
m_savePath = path; m_session->handleTorrentSavePathChanged(this);
m_session->handleTorrentSavePathChanged(this);
}
} }
void TorrentHandle::forceReannounce(int index) void TorrentHandle::forceReannounce(int index)
@ -1502,30 +1498,10 @@ void TorrentHandle::resume_impl(bool forced)
m_nativeHandle.resume(); m_nativeHandle.resume();
} }
void TorrentHandle::moveStorage(const QString &newPath, bool overwrite) void TorrentHandle::moveStorage(const QString &newPath, const MoveStorageMode mode)
{ {
if (isMoveInProgress()) { if (m_session->addMoveTorrentStorageJob(this, newPath, mode))
qDebug("enqueue move storage to %s", qUtf8Printable(newPath)); m_storageIsMoving = true;
m_moveStorageInfo.queuedPath = newPath;
m_moveStorageInfo.queuedOverwrite = overwrite;
}
else {
const QString oldPath = nativeActualSavePath();
if (QDir(oldPath) == QDir(newPath)) return;
qDebug("move storage: %s to %s", qUtf8Printable(oldPath), qUtf8Printable(newPath));
// Actually move the storage
#if (LIBTORRENT_VERSION_NUM < 10200)
m_nativeHandle.move_storage(newPath.toUtf8().constData()
, (overwrite ? lt::always_replace_files : lt::dont_replace));
#else
m_nativeHandle.move_storage(newPath.toUtf8().constData()
, (overwrite ? lt::move_flags_t::always_replace_files : lt::move_flags_t::dont_replace));
#endif
m_moveStorageInfo.oldPath = oldPath;
m_moveStorageInfo.newPath = newPath;
updateState();
}
} }
void TorrentHandle::renameFile(const int index, const QString &name) void TorrentHandle::renameFile(const int index, const QString &name)
@ -1540,66 +1516,18 @@ void TorrentHandle::handleStateUpdate(const lt::torrent_status &nativeStatus)
updateStatus(nativeStatus); updateStatus(nativeStatus);
} }
void TorrentHandle::handleStorageMovedAlert(const lt::storage_moved_alert *p) void TorrentHandle::handleStorageMoved(const QString &newPath, const QString &errorMessage)
{ {
if (!isMoveInProgress()) { m_storageIsMoving = false;
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
return;
}
const QString newPath(p->storage_path()); if (!errorMessage.isEmpty())
if (newPath != m_moveStorageInfo.newPath) { LogMsg(tr("Could not move torrent: %1. Reason: %2").arg(name(), errorMessage), Log::CRITICAL);
qWarning() << Q_FUNC_INFO << ": New path doesn't match a path in a queue."; else
return; LogMsg(tr("Successfully moved torrent: %1. New path: %2").arg(name(), newPath));
}
LogMsg(tr("Successfully moved torrent: %1. New path: %2").arg(name(), m_moveStorageInfo.newPath));
const QDir oldDir {m_moveStorageInfo.oldPath};
if ((oldDir == QDir(m_session->torrentTempPath(info())))
&& (oldDir != QDir(m_session->tempPath()))) {
// torrent without root folder still has it in its temporary save path
// so its temp path isn't equal to temp path root
qDebug() << "Removing torrent temp folder:" << m_moveStorageInfo.oldPath;
Utils::Fs::smartRemoveEmptyFolderTree(m_moveStorageInfo.oldPath);
}
m_moveStorageInfo.newPath.clear();
updateStatus();
if (!m_moveStorageInfo.queuedPath.isEmpty()) {
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
m_moveStorageInfo.queuedPath.clear();
}
if (!useTempPath()) {
m_savePath = newPath;
m_session->handleTorrentSavePathChanged(this);
}
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
m_moveFinishedTriggers.takeFirst()();
}
void TorrentHandle::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p)
{
if (!isMoveInProgress()) {
qWarning() << "Unexpected " << Q_FUNC_INFO << " call.";
return;
}
LogMsg(tr("Could not move torrent: '%1'. Reason: %2")
.arg(name(), QString::fromStdString(p->message())), Log::CRITICAL);
m_moveStorageInfo.newPath.clear();
updateStatus(); updateStatus();
if (!m_moveStorageInfo.queuedPath.isEmpty()) { while ((m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
moveStorage(m_moveStorageInfo.queuedPath, m_moveStorageInfo.queuedOverwrite);
m_moveStorageInfo.queuedPath.clear();
}
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
m_moveFinishedTriggers.takeFirst()(); m_moveFinishedTriggers.takeFirst()();
} }
@ -1922,7 +1850,7 @@ void TorrentHandle::handleTempPathChanged()
void TorrentHandle::handleCategorySavePathChanged() void TorrentHandle::handleCategorySavePathChanged()
{ {
if (m_useAutoTMM) if (m_useAutoTMM)
move_impl(m_session->categorySavePath(m_category), true); move_impl(m_session->categorySavePath(m_category), MoveStorageMode::Overwrite);
} }
void TorrentHandle::handleAppendExtensionToggled() void TorrentHandle::handleAppendExtensionToggled()
@ -1953,12 +1881,6 @@ void TorrentHandle::handleAlert(const lt::alert *a)
case lt::save_resume_data_failed_alert::alert_type: case lt::save_resume_data_failed_alert::alert_type:
handleSaveResumeDataFailedAlert(static_cast<const lt::save_resume_data_failed_alert*>(a)); handleSaveResumeDataFailedAlert(static_cast<const lt::save_resume_data_failed_alert*>(a));
break; break;
case lt::storage_moved_alert::alert_type:
handleStorageMovedAlert(static_cast<const lt::storage_moved_alert*>(a));
break;
case lt::storage_moved_failed_alert::alert_type:
handleStorageMovedFailedAlert(static_cast<const lt::storage_moved_failed_alert*>(a));
break;
case lt::torrent_paused_alert::alert_type: case lt::torrent_paused_alert::alert_type:
handleTorrentPausedAlert(static_cast<const lt::torrent_paused_alert*>(a)); handleTorrentPausedAlert(static_cast<const lt::torrent_paused_alert*>(a));
break; break;
@ -2028,19 +1950,27 @@ void TorrentHandle::adjustActualSavePath()
void TorrentHandle::adjustActualSavePath_impl() void TorrentHandle::adjustActualSavePath_impl()
{ {
QString path; const bool needUseTempDir = useTempPath();
if (!useTempPath()) { const QDir tempDir {m_session->torrentTempPath(info())};
// Disabling temp dir const QDir currentDir {actualStorageLocation()};
// Moving all torrents to their destination folder const QDir targetDir {needUseTempDir ? tempDir : QDir {savePath()}};
path = savePath();
} if (targetDir == currentDir) return;
else {
// Moving all downloading torrents to temporary folder if (!needUseTempDir) {
path = m_session->torrentTempPath(info()); if ((currentDir == tempDir) && (currentDir != QDir {m_session->tempPath()})) {
qDebug() << "Moving torrent to its temporary folder:" << path; // torrent without root folder still has it in its temporary save path
// so its temp path isn't equal to temp path root
const QString currentDirPath = currentDir.absolutePath();
m_moveFinishedTriggers.append([currentDirPath]
{
qDebug() << "Removing torrent temp folder:" << currentDirPath;
Utils::Fs::smartRemoveEmptyFolderTree(currentDirPath);
});
}
} }
moveStorage(Utils::Fs::toNativePath(path), true); moveStorage(Utils::Fs::toNativePath(targetDir.absolutePath()), MoveStorageMode::Overwrite);
} }
lt::torrent_handle TorrentHandle::nativeHandle() const lt::torrent_handle TorrentHandle::nativeHandle() const
@ -2057,7 +1987,7 @@ void TorrentHandle::updateTorrentInfo()
bool TorrentHandle::isMoveInProgress() const bool TorrentHandle::isMoveInProgress() const
{ {
return !m_moveStorageInfo.newPath.isEmpty(); return m_storageIsMoving;
} }
bool TorrentHandle::useTempPath() const bool TorrentHandle::useTempPath() const

26
src/base/bittorrent/torrenthandle.h

@ -99,6 +99,12 @@ namespace BitTorrent
int numPeers = 0; int numPeers = 0;
}; };
enum class MoveStorageMode
{
KeepExistingFiles,
Overwrite
};
enum class TorrentState enum class TorrentState
{ {
Unknown = -1, Unknown = -1,
@ -345,6 +351,7 @@ namespace BitTorrent
void handleCategorySavePathChanged(); void handleCategorySavePathChanged();
void handleAppendExtensionToggled(); void handleAppendExtensionToggled();
void saveResumeData(); void saveResumeData();
void handleStorageMoved(const QString &newPath, const QString &errorMessage);
/** /**
* @brief fraction of file pieces that are available at least from one peer * @brief fraction of file pieces that are available at least from one peer
@ -376,8 +383,6 @@ namespace BitTorrent
void handlePerformanceAlert(const lt::performance_alert *p) const; void handlePerformanceAlert(const lt::performance_alert *p) const;
void handleSaveResumeDataAlert(const lt::save_resume_data_alert *p); void handleSaveResumeDataAlert(const lt::save_resume_data_alert *p);
void handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p); void handleSaveResumeDataFailedAlert(const lt::save_resume_data_failed_alert *p);
void handleStorageMovedAlert(const lt::storage_moved_alert *p);
void handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p);
void handleTorrentCheckedAlert(const lt::torrent_checked_alert *p); void handleTorrentCheckedAlert(const lt::torrent_checked_alert *p);
void handleTorrentFinishedAlert(const lt::torrent_finished_alert *p); void handleTorrentFinishedAlert(const lt::torrent_finished_alert *p);
void handleTorrentPausedAlert(const lt::torrent_paused_alert *p); void handleTorrentPausedAlert(const lt::torrent_paused_alert *p);
@ -388,14 +393,14 @@ namespace BitTorrent
void resume_impl(bool forced); void resume_impl(bool forced);
bool isMoveInProgress() const; bool isMoveInProgress() const;
QString nativeActualSavePath() const; QString actualStorageLocation() const;
bool isAutoManaged() const; bool isAutoManaged() const;
void setAutoManaged(bool enable); void setAutoManaged(bool enable);
void adjustActualSavePath(); void adjustActualSavePath();
void adjustActualSavePath_impl(); void adjustActualSavePath_impl();
void move_impl(QString path, bool overwrite); void move_impl(QString path, MoveStorageMode mode);
void moveStorage(const QString &newPath, bool overwrite); void moveStorage(const QString &newPath, MoveStorageMode mode);
void manageIncompleteFiles(); void manageIncompleteFiles();
void setFirstLastPiecePriorityImpl(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {}); void setFirstLastPiecePriorityImpl(bool enabled, const QVector<DownloadPriority> &updatedFilePrio = {});
@ -408,16 +413,7 @@ namespace BitTorrent
InfoHash m_hash; InfoHash m_hash;
struct bool m_storageIsMoving = false;
{
QString oldPath;
QString newPath;
// queuedPath is where files should be moved to,
// when current moving is completed
QString queuedPath;
bool queuedOverwrite = true;
} m_moveStorageInfo;
// m_moveFinishedTriggers is activated only when the following conditions are met: // m_moveFinishedTriggers is activated only when the following conditions are met:
// all file rename jobs complete, all file move jobs complete // all file rename jobs complete, all file move jobs complete
QQueue<EventTrigger> m_moveFinishedTriggers; QQueue<EventTrigger> m_moveFinishedTriggers;

3
src/gui/transferlistwidget.cpp

@ -507,12 +507,9 @@ void TransferListWidget::setSelectedTorrentsLocation()
if (torrents.isEmpty()) return; if (torrents.isEmpty()) return;
const QString oldLocation = torrents[0]->savePath(); const QString oldLocation = torrents[0]->savePath();
qDebug("Old location is %s", qUtf8Printable(oldLocation));
const QString newLocation = QFileDialog::getExistingDirectory(this, tr("Choose save path"), oldLocation, const QString newLocation = QFileDialog::getExistingDirectory(this, tr("Choose save path"), oldLocation,
QFileDialog::DontConfirmOverwrite | QFileDialog::ShowDirsOnly | QFileDialog::HideNameFilterDetails); QFileDialog::DontConfirmOverwrite | QFileDialog::ShowDirsOnly | QFileDialog::HideNameFilterDetails);
if (newLocation.isEmpty() || !QDir(newLocation).exists()) return; if (newLocation.isEmpty() || !QDir(newLocation).exists()) return;
qDebug("New location is %s", qUtf8Printable(newLocation));
// Actually move storage // Actually move storage
for (BitTorrent::TorrentHandle *const torrent : torrents) { for (BitTorrent::TorrentHandle *const torrent : torrents) {

Loading…
Cancel
Save