mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-04 22:52:33 -06:00
Make TorrentInfo immutable
This commit is contained in:
@@ -72,6 +72,51 @@ namespace
|
||||
{
|
||||
return SettingsStorage::instance();
|
||||
}
|
||||
|
||||
class FileStorageAdaptor final : public BitTorrent::AbstractFileStorage
|
||||
{
|
||||
public:
|
||||
FileStorageAdaptor(const BitTorrent::TorrentInfo &torrentInfo, QStringList &filePaths)
|
||||
: m_torrentInfo {torrentInfo}
|
||||
, m_filePaths {filePaths}
|
||||
{
|
||||
Q_ASSERT(filePaths.isEmpty() || (filePaths.size() == torrentInfo.filesCount()));
|
||||
}
|
||||
|
||||
int filesCount() const override
|
||||
{
|
||||
return m_torrentInfo.filesCount();
|
||||
}
|
||||
|
||||
qlonglong fileSize(const int index) const override
|
||||
{
|
||||
Q_ASSERT((index >= 0) && (index < filesCount()));
|
||||
return m_torrentInfo.fileSize(index);
|
||||
}
|
||||
|
||||
QString filePath(const int index) const override
|
||||
{
|
||||
Q_ASSERT((index >= 0) && (index < filesCount()));
|
||||
return (m_filePaths.isEmpty() ? m_torrentInfo.filePath(index) : m_filePaths.at(index));
|
||||
}
|
||||
|
||||
void renameFile(const int index, const QString &newFilePath) override
|
||||
{
|
||||
Q_ASSERT((index >= 0) && (index < filesCount()));
|
||||
const QString currentFilePath = filePath(index);
|
||||
if (currentFilePath == newFilePath)
|
||||
return;
|
||||
|
||||
if (m_filePaths.isEmpty())
|
||||
m_filePaths = m_torrentInfo.filePaths();
|
||||
|
||||
m_filePaths[index] = newFilePath;
|
||||
}
|
||||
|
||||
private:
|
||||
const BitTorrent::TorrentInfo &m_torrentInfo;
|
||||
QStringList &m_filePaths;
|
||||
};
|
||||
}
|
||||
|
||||
const int AddNewTorrentDialog::minPathHistoryLength;
|
||||
@@ -146,10 +191,8 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP
|
||||
// Signal / slots
|
||||
connect(m_ui->doNotDeleteTorrentCheckBox, &QCheckBox::clicked, this, &AddNewTorrentDialog::doNotDeleteTorrentClicked);
|
||||
QShortcut *editHotkey = new QShortcut(Qt::Key_F2, m_ui->contentTreeView, nullptr, nullptr, Qt::WidgetShortcut);
|
||||
connect(editHotkey, &QShortcut::activated
|
||||
, this, [this]() { m_ui->contentTreeView->renameSelectedFile(m_torrentInfo); });
|
||||
connect(m_ui->contentTreeView, &QAbstractItemView::doubleClicked
|
||||
, this, [this]() { m_ui->contentTreeView->renameSelectedFile(m_torrentInfo); });
|
||||
connect(editHotkey, &QShortcut::activated, this, &AddNewTorrentDialog::renameSelectedFile);
|
||||
connect(m_ui->contentTreeView, &QAbstractItemView::doubleClicked, this, &AddNewTorrentDialog::renameSelectedFile);
|
||||
|
||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
|
||||
}
|
||||
@@ -251,7 +294,6 @@ bool AddNewTorrentDialog::loadTorrentFile(const QString &torrentPath)
|
||||
: torrentPath;
|
||||
|
||||
const nonstd::expected<BitTorrent::TorrentInfo, QString> result = BitTorrent::TorrentInfo::loadFromFile(decodedPath);
|
||||
m_torrentInfo = result.value_or(BitTorrent::TorrentInfo());
|
||||
if (!result)
|
||||
{
|
||||
RaisedMessageBox::critical(this, tr("Invalid torrent")
|
||||
@@ -260,6 +302,7 @@ bool AddNewTorrentDialog::loadTorrentFile(const QString &torrentPath)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_torrentInfo = result.value();
|
||||
m_torrentGuard = std::make_unique<TorrentFileGuard>(decodedPath);
|
||||
|
||||
return loadTorrentImpl();
|
||||
@@ -267,7 +310,6 @@ bool AddNewTorrentDialog::loadTorrentFile(const QString &torrentPath)
|
||||
|
||||
bool AddNewTorrentDialog::loadTorrentImpl()
|
||||
{
|
||||
m_hasMetadata = true;
|
||||
const auto torrentID = BitTorrent::TorrentID::fromInfoHash(m_torrentInfo.infoHash());
|
||||
|
||||
// Prevent showing the dialog if download is already present
|
||||
@@ -398,7 +440,7 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
|
||||
// Determine torrent size
|
||||
qlonglong torrentSize = 0;
|
||||
|
||||
if (m_hasMetadata)
|
||||
if (hasMetadata())
|
||||
{
|
||||
if (m_contentModel)
|
||||
{
|
||||
@@ -457,7 +499,7 @@ void AddNewTorrentDialog::setSavePath(const QString &newPath)
|
||||
|
||||
void AddNewTorrentDialog::saveTorrentFile()
|
||||
{
|
||||
Q_ASSERT(m_hasMetadata);
|
||||
Q_ASSERT(hasMetadata());
|
||||
|
||||
const QString torrentFileExtension {C_TORRENT_FILE_EXTENSION};
|
||||
const QString filter {tr("Torrent file (*%1)").arg(torrentFileExtension)};
|
||||
@@ -479,6 +521,11 @@ void AddNewTorrentDialog::saveTorrentFile()
|
||||
}
|
||||
}
|
||||
|
||||
bool AddNewTorrentDialog::hasMetadata() const
|
||||
{
|
||||
return m_torrentInfo.isValid();
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::populateSavePathComboBox()
|
||||
{
|
||||
m_ui->savePath->clear();
|
||||
@@ -548,8 +595,7 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &)
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
if (selectedRows.size() == 1)
|
||||
{
|
||||
menu->addAction(UIThemeManager::instance()->getIcon("edit-rename"), tr("Rename...")
|
||||
, this, [this]() { m_ui->contentTreeView->renameSelectedFile(m_torrentInfo); });
|
||||
menu->addAction(UIThemeManager::instance()->getIcon("edit-rename"), tr("Rename..."), this, &AddNewTorrentDialog::renameSelectedFile);
|
||||
menu->addSeparator();
|
||||
|
||||
QMenu *priorityMenu = menu->addMenu(tr("Priority"));
|
||||
@@ -634,7 +680,7 @@ void AddNewTorrentDialog::accept()
|
||||
setEnabled(!m_ui->checkBoxNeverShow->isChecked());
|
||||
|
||||
// Add torrent
|
||||
if (!m_hasMetadata)
|
||||
if (!hasMetadata())
|
||||
BitTorrent::Session::instance()->addTorrent(m_magnetURI, m_torrentParams);
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(m_torrentInfo, m_torrentParams);
|
||||
@@ -645,7 +691,7 @@ void AddNewTorrentDialog::accept()
|
||||
|
||||
void AddNewTorrentDialog::reject()
|
||||
{
|
||||
if (!m_hasMetadata)
|
||||
if (!hasMetadata())
|
||||
{
|
||||
setMetadataProgressIndicator(false);
|
||||
BitTorrent::Session::instance()->cancelDownloadMetadata(m_magnetURI.infoHash().toTorrentID());
|
||||
@@ -660,16 +706,8 @@ void AddNewTorrentDialog::updateMetadata(const BitTorrent::TorrentInfo &metadata
|
||||
|
||||
disconnect(BitTorrent::Session::instance(), &BitTorrent::Session::metadataDownloaded, this, &AddNewTorrentDialog::updateMetadata);
|
||||
|
||||
if (!metadata.isValid())
|
||||
{
|
||||
RaisedMessageBox::critical(this, tr("I/O Error"), ("Invalid metadata."));
|
||||
setMetadataProgressIndicator(false, tr("Invalid metadata"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Good to go
|
||||
m_torrentInfo = metadata;
|
||||
m_hasMetadata = true;
|
||||
setMetadataProgressIndicator(true, tr("Parsing metadata..."));
|
||||
|
||||
// Update UI
|
||||
@@ -694,7 +732,7 @@ void AddNewTorrentDialog::setMetadataProgressIndicator(bool visibleIndicator, co
|
||||
|
||||
void AddNewTorrentDialog::setupTreeview()
|
||||
{
|
||||
if (!m_hasMetadata)
|
||||
if (!hasMetadata())
|
||||
{
|
||||
m_ui->labelCommentData->setText(tr("Not Available", "This comment is unavailable"));
|
||||
m_ui->labelDateData->setText(tr("Not Available", "This date is unavailable"));
|
||||
@@ -719,7 +757,7 @@ void AddNewTorrentDialog::setupTreeview()
|
||||
connect(m_ui->contentTreeView, &QWidget::customContextMenuRequested, this, &AddNewTorrentDialog::displayContentTreeMenu);
|
||||
|
||||
// List files in torrent
|
||||
m_contentModel->model()->setupModelData(m_torrentInfo);
|
||||
m_contentModel->model()->setupModelData(FileStorageAdaptor(m_torrentInfo, m_torrentParams.filePaths));
|
||||
if (const QByteArray state = m_storeTreeHeaderState; !state.isEmpty())
|
||||
m_ui->contentTreeView->header()->restoreState(state);
|
||||
|
||||
@@ -747,7 +785,6 @@ void AddNewTorrentDialog::handleDownloadFinished(const Net::DownloadResult &down
|
||||
case Net::DownloadStatus::Success:
|
||||
{
|
||||
const nonstd::expected<BitTorrent::TorrentInfo, QString> result = BitTorrent::TorrentInfo::load(downloadResult.data);
|
||||
m_torrentInfo = result.value_or(BitTorrent::TorrentInfo());
|
||||
if (!result)
|
||||
{
|
||||
RaisedMessageBox::critical(this, tr("Invalid torrent"), tr("Failed to load from URL: %1.\nError: %2")
|
||||
@@ -755,6 +792,7 @@ void AddNewTorrentDialog::handleDownloadFinished(const Net::DownloadResult &down
|
||||
return;
|
||||
}
|
||||
|
||||
m_torrentInfo = result.value();
|
||||
m_torrentGuard = std::make_unique<TorrentFileGuard>();
|
||||
|
||||
if (loadTorrentImpl())
|
||||
@@ -800,3 +838,12 @@ void AddNewTorrentDialog::doNotDeleteTorrentClicked(bool checked)
|
||||
{
|
||||
m_torrentGuard->setAutoRemove(!checked);
|
||||
}
|
||||
|
||||
void AddNewTorrentDialog::renameSelectedFile()
|
||||
{
|
||||
if (hasMetadata())
|
||||
{
|
||||
FileStorageAdaptor fileStorageAdaptor {m_torrentInfo, m_torrentParams.filePaths};
|
||||
m_ui->contentTreeView->renameSelectedFile(fileStorageAdaptor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ private slots:
|
||||
void TMMChanged(int index);
|
||||
void categoryChanged(int index);
|
||||
void doNotDeleteTorrentClicked(bool checked);
|
||||
void renameSelectedFile();
|
||||
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
@@ -104,13 +105,13 @@ private:
|
||||
void setupTreeview();
|
||||
void setSavePath(const QString &newPath);
|
||||
void saveTorrentFile();
|
||||
bool hasMetadata() const;
|
||||
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
Ui::AddNewTorrentDialog *m_ui;
|
||||
TorrentContentFilterModel *m_contentModel = nullptr;
|
||||
PropListDelegate *m_contentDelegate = nullptr;
|
||||
bool m_hasMetadata = false;
|
||||
BitTorrent::MagnetUri m_magnetURI;
|
||||
BitTorrent::TorrentInfo m_torrentInfo;
|
||||
int m_oldIndex = 0;
|
||||
|
||||
@@ -471,7 +471,9 @@ void PeerListWidget::updatePeer(const BitTorrent::Torrent *torrent, const BitTor
|
||||
setModelData(row, PeerListColumns::TOT_UP, totalUp, peer.totalUpload(), intDataTextAlignment);
|
||||
setModelData(row, PeerListColumns::RELEVANCE, (Utils::String::fromDouble(peer.relevance() * 100, 1) + '%'), peer.relevance(), intDataTextAlignment);
|
||||
|
||||
const QStringList downloadingFiles {torrent->info().filesForPiece(peer.downloadingPieceIndex())};
|
||||
const QStringList downloadingFiles {torrent->hasMetadata()
|
||||
? torrent->info().filesForPiece(peer.downloadingPieceIndex())
|
||||
: QStringList()};
|
||||
const QString downloadingFilesDisplayValue = downloadingFiles.join(';');
|
||||
setModelData(row, PeerListColumns::DOWNLOADING_PIECE, downloadingFilesDisplayValue, downloadingFilesDisplayValue, {}, downloadingFiles.join(QLatin1Char('\n')));
|
||||
|
||||
|
||||
@@ -256,13 +256,14 @@ void PiecesBar::showToolTip(const QHelpEvent *e)
|
||||
const bool showDetailedInformation = QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||||
if (showDetailedInformation && m_torrent->hasMetadata())
|
||||
{
|
||||
const BitTorrent::TorrentInfo torrentInfo = m_torrent->info();
|
||||
const int imagePos = e->pos().x() - borderWidth;
|
||||
if ((imagePos >=0) && (imagePos < m_image.width()))
|
||||
{
|
||||
stream << "<html><body>";
|
||||
PieceIndexToImagePos transform {m_torrent->info(), m_image};
|
||||
PieceIndexToImagePos transform {torrentInfo, m_image};
|
||||
int pieceIndex = transform.pieceIndex(imagePos);
|
||||
const QVector<int> files {m_torrent->info().fileIndicesForPiece(pieceIndex)};
|
||||
const QVector<int> files {torrentInfo.fileIndicesForPiece(pieceIndex)};
|
||||
|
||||
QString tooltipTitle;
|
||||
if (files.count() > 1)
|
||||
@@ -271,7 +272,7 @@ void PiecesBar::showToolTip(const QHelpEvent *e)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_torrent->info().fileSize(files.front()) == m_torrent->info().pieceLength(pieceIndex))
|
||||
if (torrentInfo.fileSize(files.front()) == torrentInfo.pieceLength(pieceIndex))
|
||||
tooltipTitle = tr("File in this piece");
|
||||
else
|
||||
tooltipTitle = tr("File in these pieces");
|
||||
@@ -281,8 +282,8 @@ void PiecesBar::showToolTip(const QHelpEvent *e)
|
||||
|
||||
for (int f : files)
|
||||
{
|
||||
const QString filePath {m_torrent->info().filePath(f)};
|
||||
renderer(Utils::Misc::friendlyUnit(m_torrent->info().fileSize(f)), filePath);
|
||||
const QString filePath {torrentInfo.filePath(f)};
|
||||
renderer(Utils::Misc::friendlyUnit(torrentInfo.fileSize(f)), filePath);
|
||||
}
|
||||
stream << "</body></html>";
|
||||
}
|
||||
@@ -306,13 +307,14 @@ void PiecesBar::highlightFile(int imagePos)
|
||||
if (!m_torrent || !m_torrent->hasMetadata() || (imagePos < 0) || (imagePos >= m_image.width()))
|
||||
return;
|
||||
|
||||
PieceIndexToImagePos transform {m_torrent->info(), m_image};
|
||||
const BitTorrent::TorrentInfo torrentInfo = m_torrent->info();
|
||||
PieceIndexToImagePos transform {torrentInfo, m_image};
|
||||
|
||||
int pieceIndex = transform.pieceIndex(imagePos);
|
||||
QVector<int> fileIndices {m_torrent->info().fileIndicesForPiece(pieceIndex)};
|
||||
QVector<int> fileIndices {torrentInfo.fileIndicesForPiece(pieceIndex)};
|
||||
if (fileIndices.count() == 1)
|
||||
{
|
||||
BitTorrent::TorrentInfo::PieceRange filePieces = m_torrent->info().filePieces(fileIndices.first());
|
||||
BitTorrent::TorrentInfo::PieceRange filePieces = torrentInfo.filePieces(fileIndices.first());
|
||||
|
||||
ImageRange imageRange = transform.imagePos(filePieces);
|
||||
QRect newHighlightedRegion {imageRange.first(), 0, imageRange.size(), m_image.height()};
|
||||
|
||||
@@ -528,7 +528,7 @@ void PropertiesWidget::loadDynamicData()
|
||||
if (!isContentInitialized)
|
||||
{
|
||||
// List files in torrent
|
||||
m_propListModel->model()->setupModelData(m_torrent->info());
|
||||
m_propListModel->model()->setupModelData(*m_torrent);
|
||||
// Load file priorities
|
||||
m_propListModel->model()->updateFilesPriorities(m_torrent->filePriorities());
|
||||
// Update file progress/availability
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
#include <QPixmapCache>
|
||||
#endif
|
||||
|
||||
#include "base/bittorrent/abstractfilestorage.h"
|
||||
#include "base/bittorrent/downloadpriority.h"
|
||||
#include "base/bittorrent/torrentinfo.h"
|
||||
#include "base/global.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "torrentcontentmodelfile.h"
|
||||
@@ -485,7 +485,7 @@ void TorrentContentModel::clear()
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void TorrentContentModel::setupModelData(const BitTorrent::TorrentInfo &info)
|
||||
void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &info)
|
||||
{
|
||||
qDebug("setup model data called");
|
||||
const int filesCount = info.filesCount();
|
||||
|
||||
@@ -41,7 +41,7 @@ class TorrentContentModelFile;
|
||||
|
||||
namespace BitTorrent
|
||||
{
|
||||
class TorrentInfo;
|
||||
class AbstractFileStorage;
|
||||
}
|
||||
|
||||
class TorrentContentModel final : public QAbstractItemModel
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
QModelIndex parent(const QModelIndex &index) const override;
|
||||
int rowCount(const QModelIndex &parent = {}) const override;
|
||||
void clear();
|
||||
void setupModelData(const BitTorrent::TorrentInfo &info);
|
||||
void setupModelData(const BitTorrent::AbstractFileStorage &info);
|
||||
|
||||
signals:
|
||||
void filteredFilesChanged();
|
||||
|
||||
Reference in New Issue
Block a user