diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index f3de1d9b0..07bb95439 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -123,7 +123,6 @@ add_library(qbt_base STATIC bittorrent/speedmonitor.cpp bittorrent/statistics.cpp bittorrent/torrent.cpp - bittorrent/torrentcontentlayout.cpp bittorrent/torrentcreatorthread.cpp bittorrent/torrentimpl.cpp bittorrent/torrentinfo.cpp diff --git a/src/base/base.pri b/src/base/base.pri index 0893f282b..01c5b9ccc 100644 --- a/src/base/base.pri +++ b/src/base/base.pri @@ -123,7 +123,6 @@ SOURCES += \ $$PWD/bittorrent/speedmonitor.cpp \ $$PWD/bittorrent/statistics.cpp \ $$PWD/bittorrent/torrent.cpp \ - $$PWD/bittorrent/torrentcontentlayout.cpp \ $$PWD/bittorrent/torrentcreatorthread.cpp \ $$PWD/bittorrent/torrentimpl.cpp \ $$PWD/bittorrent/torrentinfo.cpp \ diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index de1aa89bf..48996599e 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -2255,10 +2255,25 @@ bool Session::addTorrent_impl(const std::variant &source Q_ASSERT(addTorrentParams.filePaths.isEmpty() || (addTorrentParams.filePaths.size() == torrentInfo.filesCount())); - const TorrentContentLayout contentLayout = ((loadTorrentParams.contentLayout == TorrentContentLayout::Original) - ? detectContentLayout(torrentInfo.filePaths()) : loadTorrentParams.contentLayout); - PathList filePaths = (!addTorrentParams.filePaths.isEmpty() ? addTorrentParams.filePaths : torrentInfo.filePaths()); - applyContentLayout(filePaths, contentLayout, Path::findRootFolder(torrentInfo.filePaths())); + PathList filePaths = addTorrentParams.filePaths; + if (filePaths.isEmpty()) + { + filePaths = torrentInfo.filePaths(); + if (loadTorrentParams.contentLayout != TorrentContentLayout::Original) + { + const Path originalRootFolder = Path::findRootFolder(filePaths); + const auto originalContentLayout = (originalRootFolder.isEmpty() + ? TorrentContentLayout::NoSubfolder + : TorrentContentLayout::Subfolder); + if (loadTorrentParams.contentLayout != originalContentLayout) + { + if (loadTorrentParams.contentLayout == TorrentContentLayout::NoSubfolder) + Path::stripRootFolder(filePaths); + else + Path::addRootFolder(filePaths, filePaths.at(0).removedExtension()); + } + } + } // if torrent name wasn't explicitly set we handle the case of // initial renaming of torrent content and rename torrent accordingly diff --git a/src/base/bittorrent/torrentcontentlayout.cpp b/src/base/bittorrent/torrentcontentlayout.cpp deleted file mode 100644 index 8b3611ddd..000000000 --- a/src/base/bittorrent/torrentcontentlayout.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2020-2021 Vladimir Golovnev - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, the copyright holders give permission to - * link this program with the OpenSSL project's "OpenSSL" library (or with - * modified versions of it that use the same license as the "OpenSSL" library), - * and distribute the linked executables. You must obey the GNU General Public - * License in all respects for all of the code used other than "OpenSSL". If you - * modify file(s), you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ - -#include "torrentcontentlayout.h" - -#include "base/utils/fs.h" - -namespace -{ - Path removeExtension(const Path &fileName) - { - Path result = fileName; - result.removeExtension(); - return result; - } -} - -BitTorrent::TorrentContentLayout BitTorrent::detectContentLayout(const PathList &filePaths) -{ - const Path rootFolder = Path::findRootFolder(filePaths); - return (rootFolder.isEmpty() - ? TorrentContentLayout::NoSubfolder - : TorrentContentLayout::Subfolder); -} - -void BitTorrent::applyContentLayout(PathList &filePaths, const BitTorrent::TorrentContentLayout contentLayout, const Path &rootFolder) -{ - Q_ASSERT(!filePaths.isEmpty()); - - switch (contentLayout) - { - case TorrentContentLayout::Subfolder: - if (Path::findRootFolder(filePaths).isEmpty()) - Path::addRootFolder(filePaths, !rootFolder.isEmpty() ? rootFolder : removeExtension(filePaths.at(0))); - break; - - case TorrentContentLayout::NoSubfolder: - Path::stripRootFolder(filePaths); - break; - - default: - break; - } -} diff --git a/src/base/bittorrent/torrentcontentlayout.h b/src/base/bittorrent/torrentcontentlayout.h index 9ebb35e2c..438892b0c 100644 --- a/src/base/bittorrent/torrentcontentlayout.h +++ b/src/base/bittorrent/torrentcontentlayout.h @@ -51,7 +51,4 @@ namespace BitTorrent Q_ENUM_NS(TorrentContentLayout) } - - TorrentContentLayout detectContentLayout(const PathList &filePaths); - void applyContentLayout(PathList &filePaths, TorrentContentLayout contentLayout, const Path &rootFolder = {}); } diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 00e720ccc..174bb91e0 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -1769,11 +1769,24 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p) TorrentInfo metadata = TorrentInfo(*m_nativeHandle.torrent_file()); - const auto nativeIndexes = metadata.nativeIndexes(); - PathList filePaths = metadata.filePaths(); - applyContentLayout(filePaths, m_contentLayout); - const auto &renamedFiles = m_ltAddTorrentParams.renamed_files; + PathList filePaths = metadata.filePaths(); + if (renamedFiles.empty() && (m_contentLayout != TorrentContentLayout::Original)) + { + const Path originalRootFolder = Path::findRootFolder(filePaths); + const auto originalContentLayout = (originalRootFolder.isEmpty() + ? TorrentContentLayout::NoSubfolder + : TorrentContentLayout::Subfolder); + if (m_contentLayout != originalContentLayout) + { + if (m_contentLayout == TorrentContentLayout::NoSubfolder) + Path::stripRootFolder(filePaths); + else + Path::addRootFolder(filePaths, filePaths.at(0).removedExtension()); + } + } + + const auto nativeIndexes = metadata.nativeIndexes(); m_indexMap.reserve(filePaths.size()); for (int i = 0; i < filePaths.size(); ++i) { diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 0fee0d8e1..84918a65a 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -51,6 +51,7 @@ #include "infohash.h" #include "speedmonitor.h" #include "torrent.h" +#include "torrentcontentlayout.h" #include "torrentinfo.h" namespace BitTorrent diff --git a/src/base/bittorrent/torrentinfo.cpp b/src/base/bittorrent/torrentinfo.cpp index 606c56a4e..71ec11486 100644 --- a/src/base/bittorrent/torrentinfo.cpp +++ b/src/base/bittorrent/torrentinfo.cpp @@ -41,6 +41,7 @@ #include #include "base/global.h" +#include "base/path.h" #include "base/utils/fs.h" #include "base/utils/io.h" #include "base/utils/misc.h" @@ -408,14 +409,6 @@ int TorrentInfo::fileIndex(const Path &filePath) const return -1; } -TorrentContentLayout TorrentInfo::contentLayout() const -{ - if (!isValid()) - return TorrentContentLayout::Original; - - return detectContentLayout(filePaths()); -} - std::shared_ptr TorrentInfo::nativeInfo() const { if (!isValid()) diff --git a/src/base/bittorrent/torrentinfo.h b/src/base/bittorrent/torrentinfo.h index 2099dc687..a357c4e2e 100644 --- a/src/base/bittorrent/torrentinfo.h +++ b/src/base/bittorrent/torrentinfo.h @@ -36,7 +36,6 @@ #include "base/3rdparty/expected.hpp" #include "base/indexrange.h" #include "base/pathfwd.h" -#include "torrentcontentlayout.h" class QByteArray; class QDateTime; @@ -99,7 +98,6 @@ namespace BitTorrent private: // returns file index or -1 if fileName is not found int fileIndex(const Path &filePath) const; - TorrentContentLayout contentLayout() const; std::shared_ptr m_nativeInfo; diff --git a/src/base/path.cpp b/src/base/path.cpp index d10658083..966cdc32b 100644 --- a/src/base/path.cpp +++ b/src/base/path.cpp @@ -181,6 +181,11 @@ void Path::removeExtension() m_pathStr.chop(extension().size()); } +Path Path::removedExtension() const +{ + return createUnchecked(m_pathStr.chopped(extension().size())); +} + void Path::removeExtension(const QString &ext) { if (hasExtension(ext)) diff --git a/src/base/path.h b/src/base/path.h index fe2172224..d372471a1 100644 --- a/src/base/path.h +++ b/src/base/path.h @@ -60,6 +60,7 @@ public: QString extension() const; bool hasExtension(const QString &ext) const; void removeExtension(); + Path removedExtension() const; void removeExtension(const QString &ext); bool hasAncestor(const Path &other) const; diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 41aab69fb..11de498dc 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -256,6 +256,38 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP m_ui->categoryComboBox->setFocus(); } +void AddNewTorrentDialog::applyContentLayout() +{ + Q_ASSERT(hasMetadata()); + Q_ASSERT(!m_torrentParams.filePaths.isEmpty()); + + const auto originalContentLayout = (m_originalRootFolder.isEmpty() + ? BitTorrent::TorrentContentLayout::NoSubfolder + : BitTorrent::TorrentContentLayout::Subfolder); + const int currentIndex = m_ui->contentLayoutComboBox->currentIndex(); + const auto contentLayout = ((currentIndex == 0) + ? originalContentLayout + : static_cast(currentIndex)); + if (contentLayout != m_currentContentLayout) + { + PathList &filePaths = m_torrentParams.filePaths; + + if (contentLayout == BitTorrent::TorrentContentLayout::NoSubfolder) + { + Path::stripRootFolder(filePaths); + } + else + { + const auto rootFolder = ((originalContentLayout == BitTorrent::TorrentContentLayout::Subfolder) + ? m_originalRootFolder + : filePaths.at(0).removedExtension()); + Path::addRootFolder(filePaths, rootFolder); + } + + m_currentContentLayout = contentLayout; + } +} + AddNewTorrentDialog::~AddNewTorrentDialog() { saveState(); @@ -538,7 +570,7 @@ void AddNewTorrentDialog::categoryChanged(int index) } } -void AddNewTorrentDialog::contentLayoutChanged(const int index) +void AddNewTorrentDialog::contentLayoutChanged() { if (!hasMetadata()) return; @@ -546,11 +578,8 @@ void AddNewTorrentDialog::contentLayoutChanged(const int index) const auto filePriorities = m_contentModel->model()->getFilePriorities(); m_contentModel->model()->clear(); - Q_ASSERT(!m_torrentParams.filePaths.isEmpty()); - const auto contentLayout = ((index == 0) - ? BitTorrent::detectContentLayout(m_torrentInfo.filePaths()) - : static_cast(index)); - BitTorrent::applyContentLayout(m_torrentParams.filePaths, contentLayout, Path::findRootFolder(m_torrentInfo.filePaths())); + applyContentLayout(); + m_contentModel->model()->setupModelData(FileStorageAdaptor(m_torrentInfo, m_torrentParams.filePaths)); m_contentModel->model()->updateFilesPriorities(filePriorities); @@ -905,12 +934,16 @@ void AddNewTorrentDialog::setupTreeview() connect(m_ui->buttonSelectAll, &QPushButton::clicked, m_contentModel, &TorrentContentFilterModel::selectAll); connect(m_ui->buttonSelectNone, &QPushButton::clicked, m_contentModel, &TorrentContentFilterModel::selectNone); - const auto contentLayout = ((m_ui->contentLayoutComboBox->currentIndex() == 0) - ? BitTorrent::detectContentLayout(m_torrentInfo.filePaths()) - : static_cast(m_ui->contentLayoutComboBox->currentIndex())); + if (m_torrentParams.filePaths.isEmpty()) m_torrentParams.filePaths = m_torrentInfo.filePaths(); - BitTorrent::applyContentLayout(m_torrentParams.filePaths, contentLayout, Path::findRootFolder(m_torrentInfo.filePaths())); + + m_originalRootFolder = Path::findRootFolder(m_torrentInfo.filePaths()); + m_currentContentLayout = (m_originalRootFolder.isEmpty() + ? BitTorrent::TorrentContentLayout::NoSubfolder + : BitTorrent::TorrentContentLayout::Subfolder); + applyContentLayout(); + // List files in torrent m_contentModel->model()->setupModelData(FileStorageAdaptor(m_torrentInfo, m_torrentParams.filePaths)); if (const QByteArray state = m_storeTreeHeaderState; !state.isEmpty()) diff --git a/src/gui/addnewtorrentdialog.h b/src/gui/addnewtorrentdialog.h index 3ddfa4d00..a7bd28807 100644 --- a/src/gui/addnewtorrentdialog.h +++ b/src/gui/addnewtorrentdialog.h @@ -35,6 +35,7 @@ #include "base/bittorrent/addtorrentparams.h" #include "base/bittorrent/magneturi.h" #include "base/bittorrent/torrentinfo.h" +#include "base/path.h" #include "base/settingvalue.h" namespace BitTorrent @@ -88,7 +89,7 @@ private slots: void handleDownloadFinished(const Net::DownloadResult &downloadResult); void TMMChanged(int index); void categoryChanged(int index); - void contentLayoutChanged(int index); + void contentLayoutChanged(); void doNotDeleteTorrentClicked(bool checked); void renameSelectedFile(); @@ -97,6 +98,8 @@ private slots: private: explicit AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent); + + void applyContentLayout(); bool loadTorrentFile(const QString &source); bool loadTorrentImpl(); bool loadMagnet(const BitTorrent::MagnetUri &magnetUri); @@ -115,6 +118,8 @@ private: PropListDelegate *m_contentDelegate = nullptr; BitTorrent::MagnetUri m_magnetURI; BitTorrent::TorrentInfo m_torrentInfo; + Path m_originalRootFolder; + BitTorrent::TorrentContentLayout m_currentContentLayout; int m_savePathIndex = -1; int m_downloadPathIndex = -1; bool m_useDownloadPath = false;