diff --git a/src/base/bittorrent/torrenthandle.cpp b/src/base/bittorrent/torrenthandle.cpp index 93aa75d60..2da728bcf 100644 --- a/src/base/bittorrent/torrenthandle.cpp +++ b/src/base/bittorrent/torrenthandle.cpp @@ -1402,6 +1402,7 @@ void TorrentHandle::setTrackerLogin(const QString &username, const QString &pass void TorrentHandle::renameFile(int index, const QString &name) { + m_oldPath[LTFileIndex {index}].push_back(filePath(index)); ++m_renameCount; qDebug() << Q_FUNC_INFO << index << name; m_nativeHandle.rename_file(index, Utils::Fs::toNativePath(name).toStdString()); @@ -1685,33 +1686,42 @@ void TorrentHandle::handleFastResumeRejectedAlert(const libtorrent::fastresume_r void TorrentHandle::handleFileRenamedAlert(const libtorrent::file_renamed_alert *p) { -#if LIBTORRENT_VERSION_NUM < 10100 - QString newName = Utils::Fs::fromNativePath(QString::fromStdString(p->name)); -#else - QString newName = Utils::Fs::fromNativePath(p->new_name()); -#endif - - // TODO: Check this! - if (filesCount() > 1) { - // Check if folders were renamed - QStringList oldPathParts = m_torrentInfo.origFilePath(p->index).split('/'); - oldPathParts.removeLast(); - QString oldPath = oldPathParts.join('/'); - QStringList newPathParts = newName.split('/'); - newPathParts.removeLast(); - QString newPath = newPathParts.join('/'); - if (!newPathParts.isEmpty() && (oldPath != newPath)) { - qDebug("oldPath(%s) != newPath(%s)", qUtf8Printable(oldPath), qUtf8Printable(newPath)); - oldPath = QString("%1/%2").arg(savePath(true), oldPath); - qDebug("Detected folder renaming, attempt to delete old folder: %s", qUtf8Printable(oldPath)); - QDir().rmpath(oldPath); - } - } - // We don't really need to call updateStatus() in this place. // All we need to do is make sure we have a valid instance of the TorrentInfo object. m_torrentInfo = TorrentInfo {m_nativeHandle.torrent_file()}; + // remove empty leftover folders + // for example renaming "a/b/c" to "d/b/c", then folders "a/b" and "a" will + // be removed if they are empty + const QString oldFilePath = m_oldPath[LTFileIndex {p->index}].takeFirst(); + const QString newFilePath = Utils::Fs::fromNativePath(p->new_name()); + + if (m_oldPath[LTFileIndex {p->index}].isEmpty()) + m_oldPath.remove(LTFileIndex {p->index}); + + QVector oldPathParts = oldFilePath.splitRef('/', QString::SkipEmptyParts); + oldPathParts.removeLast(); // drop file name part + QVector newPathParts = newFilePath.splitRef('/', QString::SkipEmptyParts); + newPathParts.removeLast(); // drop file name part + +#if defined(Q_OS_WIN) + const Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; +#else + const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; +#endif + + int pathIdx = 0; + while ((pathIdx < oldPathParts.size()) && (pathIdx < newPathParts.size())) { + if (oldPathParts[pathIdx].compare(newPathParts[pathIdx], caseSensitivity) != 0) + break; + ++pathIdx; + } + + for (int i = (oldPathParts.size() - 1); i >= pathIdx; --i) { + QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QLatin1String("/"))); + oldPathParts.removeLast(); + } + --m_renameCount; while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty()) m_moveFinishedTriggers.takeFirst()(); @@ -1719,7 +1729,13 @@ void TorrentHandle::handleFileRenamedAlert(const libtorrent::file_renamed_alert void TorrentHandle::handleFileRenameFailedAlert(const libtorrent::file_rename_failed_alert *p) { - Q_UNUSED(p); + LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"") + .arg(name(), filePath(p->index) + , QString::fromStdString(p->error.message())), Log::WARNING); + + m_oldPath[LTFileIndex {p->index}].removeFirst(); + if (m_oldPath[LTFileIndex {p->index}].isEmpty()) + m_oldPath.remove(LTFileIndex {p->index}); --m_renameCount; while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty()) diff --git a/src/base/bittorrent/torrenthandle.h b/src/base/bittorrent/torrenthandle.h index 425e688d4..c9d9d9a67 100644 --- a/src/base/bittorrent/torrenthandle.h +++ b/src/base/bittorrent/torrenthandle.h @@ -385,6 +385,12 @@ namespace BitTorrent private: typedef boost::function EventTrigger; +#if (LIBTORRENT_VERSION_NUM < 10200) + using LTFileIndex = int; +#else + using LTFileIndex = lt::file_index_t; +#endif + void updateStatus(); void updateStatus(const libtorrent::torrent_status &nativeStatus); void updateState(); @@ -446,6 +452,10 @@ namespace BitTorrent QQueue m_moveFinishedTriggers; int m_renameCount; + // Until libtorrent provide an "old_name" field in `file_renamed_alert` + // we will rely on this workaround to remove empty leftover folders + QHash> m_oldPath; + bool m_useAutoTMM; // Persistent data diff --git a/src/base/utils/string.cpp b/src/base/utils/string.cpp index 85b5b9191..59c07031b 100644 --- a/src/base/utils/string.cpp +++ b/src/base/utils/string.cpp @@ -213,3 +213,14 @@ TriStateBool Utils::String::parseTriStateBool(const QString &string) return TriStateBool::False; return TriStateBool::Undefined; } + +QString Utils::String::join(const QVector &strings, const QString &separator) +{ + if (strings.empty()) + return {}; + + QString ret = strings[0].toString(); + for (int i = 1; i < strings.count(); ++i) + ret += (separator + strings[i]); + return ret; +} diff --git a/src/base/utils/string.h b/src/base/utils/string.h index 5a1088622..3f15322da 100644 --- a/src/base/utils/string.h +++ b/src/base/utils/string.h @@ -31,6 +31,7 @@ #define UTILS_STRING_H #include +#include class QByteArray; class QLatin1String; @@ -70,6 +71,8 @@ namespace Utils bool parseBool(const QString &string, const bool defaultValue); TriStateBool parseTriStateBool(const QString &string); + + QString join(const QVector &strings, const QString &separator); } } diff --git a/src/gui/torrentcontenttreeview.cpp b/src/gui/torrentcontenttreeview.cpp index 3e65b70fd..285d3f568 100644 --- a/src/gui/torrentcontenttreeview.cpp +++ b/src/gui/torrentcontenttreeview.cpp @@ -205,15 +205,6 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentHandle *torre if (needForceRecheck) torrent->forceRecheck(); - // Remove old folder - const QString oldFullPath = torrent->savePath(true) + oldPath; - int timeout = 10; - while (!QDir().rmpath(oldFullPath) && (timeout > 0)) { - // FIXME: We should not sleep here (freezes the UI for 1 second) - QThread::msleep(100); - --timeout; - } - model->setData(modelIndex, newName); } }