35 #include <QFileDialog>
37 #include <QPushButton>
61 #include "ui_addnewtorrentdialog.h"
67 #define SETTINGS_KEY(name) "AddNewTorrentDialog/" name
84 : m_torrentInfo {torrentInfo}
85 , m_filePaths {filePaths}
87 Q_ASSERT(filePaths.isEmpty() || (filePaths.size() == torrentInfo.
filesCount()));
92 return m_torrentInfo.filesCount();
95 qlonglong
fileSize(
const int index)
const override
97 Q_ASSERT((index >= 0) && (index < filesCount()));
98 return m_torrentInfo.fileSize(index);
103 Q_ASSERT((index >= 0) && (index < filesCount()));
104 return (m_filePaths.isEmpty() ? m_torrentInfo.filePath(index) : m_filePaths.at(index));
107 void renameFile(
const int index,
const QString &newFilePath)
override
109 Q_ASSERT((index >= 0) && (index < filesCount()));
110 const QString currentFilePath = filePath(index);
111 if (currentFilePath == newFilePath)
114 if (m_filePaths.isEmpty())
115 m_filePaths = m_torrentInfo.filePaths();
117 m_filePaths[index] = newFilePath;
128 const QDir saveDir {savePath};
129 for (
int i = 0; i < fsPathEdit->
count(); ++i)
131 if (QDir(fsPathEdit->
item(i)) == saveDir)
139 int existingIndex =
indexOfPath(fsPathEdit, newPath);
140 if (existingIndex < 0)
155 const int selectedSavePathIndex = pathList.indexOf(path);
156 if (selectedSavePathIndex > -1)
157 pathList.move(selectedSavePathIndex, 0);
159 pathList.prepend(path);
170 , m_torrentParams(inParams)
172 , m_storeDefaultCategory(
SETTINGS_KEY(
"DefaultCategory"))
173 , m_storeRememberLastSavePath(
SETTINGS_KEY(
"RememberLastSavePath"))
174 #
if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
175 , m_storeTreeHeaderState(
"GUI/Qt6/" SETTINGS_KEY(
"TreeHeaderState"))
176 , m_storeSplitterState(
"GUI/Qt6/" SETTINGS_KEY(
"SplitterState"))
178 , m_storeTreeHeaderState(
SETTINGS_KEY(
"TreeHeaderState"))
184 setAttribute(Qt::WA_DeleteOnClose);
186 m_ui->lblMetaLoading->setVisible(
false);
187 m_ui->progMetaLoading->setVisible(
false);
188 m_ui->buttonSave->setVisible(
false);
192 m_ui->savePath->setDialogCaption(tr(
"Choose save path"));
193 m_ui->savePath->setMaxVisibleItems(20);
198 m_ui->downloadPath->setDialogCaption(tr(
"Choose save path"));
199 m_ui->downloadPath->setMaxVisibleItems(20);
203 m_ui->comboTTM->blockSignals(
true);
204 m_ui->comboTTM->setCurrentIndex(session->isAutoTMMDisabledByDefault() ? 0 : 1);
205 m_ui->comboTTM->blockSignals(
false);
213 m_ui->contentLayoutComboBox->setCurrentIndex(
224 QStringList categories = session->categories();
230 if (!defaultCategory.isEmpty())
231 m_ui->categoryComboBox->addItem(defaultCategory);
232 m_ui->categoryComboBox->addItem(
"");
234 for (
const QString &category :
asConst(categories))
236 m_ui->categoryComboBox->addItem(category);
238 m_ui->contentTreeView->header()->setSortIndicator(0, Qt::AscendingOrder);
242 QShortcut *editHotkey =
new QShortcut(Qt::Key_F2,
m_ui->contentTreeView,
nullptr,
nullptr, Qt::WidgetShortcut);
246 m_ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus();
279 const int defaultHistoryLength = 8;
288 if (clampedValue == oldValue)
324 const bool isLoaded = magnetUri.
isValid()
325 ? dlg->loadMagnet(magnetUri)
326 : dlg->loadTorrentFile(
source);
329 dlg->QDialog::show();
341 const QString decodedPath = torrentPath.startsWith(
"file://", Qt::CaseInsensitive)
342 ? QUrl::fromEncoded(torrentPath.toLocal8Bit()).toLocalFile()
349 , tr(
"Failed to load the torrent: %1.\nError: %2",
"Don't remove the '\n' characters. They insert a newline.")
372 RaisedMessageBox::warning(
this, tr(
"Torrent is already present"), tr(
"Torrent '%1' is already in the transfer list. Trackers haven't been merged because it is a private torrent.").arg(torrent->
name()), QMessageBox::Ok);
378 RaisedMessageBox::information(
this, tr(
"Torrent is already present"), tr(
"Torrent '%1' is already in the transfer list. Trackers have been merged.").arg(torrent->
name()), QMessageBox::Ok);
415 RaisedMessageBox::warning(
this, tr(
"Torrent is already present"), tr(
"Torrent '%1' is already in the transfer list. Trackers haven't been merged because it is a private torrent.").arg(torrent->
name()), QMessageBox::Ok);
421 RaisedMessageBox::information(
this, tr(
"Torrent is already present"), tr(
"Magnet link '%1' is already in the transfer list. Trackers have been merged.").arg(torrent->
name()), QMessageBox::Ok);
434 const QString torrentName = magnetUri.
name();
435 setWindowTitle(torrentName.isEmpty() ? tr(
"Magnet link") : torrentName);
451 QDialog::showEvent(event);
461 qlonglong torrentSize = 0;
469 for (
int i = 0; i < priorities.size(); ++i)
481 const QString sizeString = tr(
"%1 (Free space on disk: %2)").arg(
484 m_ui->labelSizeData->setText(sizeString);
499 const int currentPathIndex =
m_ui->downloadPath->currentIndex();
500 if (currentPathIndex >= 0)
514 if (
m_ui->comboTTM->currentIndex() == 1)
517 const QString categoryName =
m_ui->categoryComboBox->currentText();
519 const QString savePath = btSession->categorySavePath(categoryName);
522 const QString downloadPath = btSession->categoryDownloadPath(categoryName);
525 m_ui->groupBoxDownloadPath->setChecked(!
m_ui->downloadPath->selectedPath().isEmpty());
540 const auto contentLayout = ((index == 0)
548 QModelIndex currentIndex;
552 m_ui->contentTreeView->setExpanded(currentIndex,
true);
561 const QString filter {tr(
"Torrent file (*%1)").arg(torrentFileExtension)};
563 QString path = QFileDialog::getSaveFileName(
564 this, tr(
"Save as torrent file")
567 if (path.isEmpty())
return;
569 if (!path.endsWith(torrentFileExtension, Qt::CaseInsensitive))
570 path += torrentFileExtension;
575 QMessageBox::critical(
this, tr(
"I/O Error")
576 , tr(
"Couldn't export torrent metadata file '%1'. Reason: %2.").arg(path, result.error()));
589 m_ui->savePath->blockSignals(
true);
590 m_ui->savePath->clear();
592 if (savePathHistory.size() > 0)
594 for (
const QString &path : savePathHistory)
595 m_ui->savePath->addItem(path);
599 m_ui->savePath->addItem(btSession->savePath());
613 m_ui->savePath->setCurrentIndex(0);
618 m_ui->savePath->blockSignals(
false);
620 m_ui->downloadPath->blockSignals(
true);
621 m_ui->downloadPath->clear();
623 if (downloadPathHistory.size() > 0)
625 for (
const QString &path : downloadPathHistory)
626 m_ui->downloadPath->addItem(path);
630 m_ui->downloadPath->addItem(btSession->downloadPath());
641 m_ui->groupBoxDownloadPath->setChecked(useDownloadPath);
646 setPath(
m_ui->downloadPath, btSession->downloadPath());
648 m_ui->downloadPath->setCurrentIndex(0);
651 if (!useDownloadPath)
652 m_ui->downloadPath->setCurrentIndex(-1);
655 m_ui->downloadPath->blockSignals(
false);
656 m_ui->groupBoxDownloadPath->blockSignals(
false);
661 const QModelIndexList selectedRows =
m_ui->contentTreeView->selectionModel()->selectedRows(0);
665 const QModelIndexList selectedRows =
m_ui->contentTreeView->selectionModel()->selectedRows(0);
666 for (
const QModelIndex &index : selectedRows)
669 ,
static_cast<int>(prio));
672 const auto applyPrioritiesByOrder = [
this]()
678 const QModelIndexList selectedRows =
m_ui->contentTreeView->selectionModel()->selectedRows(0);
680 const qsizetype priorityGroups = 3;
681 const auto priorityGroupSize = std::max<qsizetype>((selectedRows.length() / priorityGroups), 1);
683 for (qsizetype i = 0; i < selectedRows.length(); ++i)
686 switch (i / priorityGroupSize)
700 const QModelIndex &index = selectedRows[i];
702 ,
static_cast<int>(priority));
706 QMenu *menu =
new QMenu(
this);
707 menu->setAttribute(Qt::WA_DeleteOnClose);
708 if (selectedRows.size() == 1)
711 menu->addSeparator();
713 QMenu *priorityMenu = menu->addMenu(tr(
"Priority"));
714 priorityMenu->addAction(tr(
"Do not download"), priorityMenu, [applyPriorities]()
718 priorityMenu->addAction(tr(
"Normal"), priorityMenu, [applyPriorities]()
722 priorityMenu->addAction(tr(
"High"), priorityMenu, [applyPriorities]()
726 priorityMenu->addAction(tr(
"Maximum"), priorityMenu, [applyPriorities]()
730 priorityMenu->addSeparator();
731 priorityMenu->addAction(tr(
"By shown file order"), priorityMenu, applyPrioritiesByOrder);
735 menu->addAction(tr(
"Do not download"), menu, [applyPriorities]()
739 menu->addAction(tr(
"Normal priority"), menu, [applyPriorities]()
743 menu->addAction(tr(
"High priority"), menu, [applyPriorities]()
747 menu->addAction(tr(
"Maximum priority"), menu, [applyPriorities]()
751 menu->addSeparator();
752 menu->addAction(tr(
"Priority by shown file order"), menu, applyPrioritiesByOrder);
755 menu->popup(QCursor::pos());
765 if (
m_ui->defaultCategoryCheckbox->isChecked())
780 const bool useAutoTMM = (
m_ui->comboTTM->currentIndex() == 1);
784 const QString savePath =
m_ui->savePath->selectedPath();
791 const QString downloadPath =
m_ui->downloadPath->selectedPath();
836 m_ui->buttonSave->setVisible(
true);
839 m_ui->buttonSave->setEnabled(
false);
840 m_ui->buttonSave->setToolTip(tr(
"Cannot create v2 torrent until its data is fully downloaded."));
847 m_ui->lblMetaLoading->setVisible(
true);
848 m_ui->lblMetaLoading->setText(labelText);
849 m_ui->progMetaLoading->setVisible(visibleIndicator);
856 m_ui->labelCommentData->setText(tr(
"Not Available",
"This comment is unavailable"));
857 m_ui->labelDateData->setText(tr(
"Not Available",
"This date is unavailable"));
874 connect(
m_ui->contentTreeView, &QAbstractItemView::clicked,
m_ui->contentTreeView
875 , qOverload<const QModelIndex &>(&QAbstractItemView::edit));
878 const auto contentLayout = ((
m_ui->contentLayoutComboBox->currentIndex() == 0)
887 m_ui->contentTreeView->header()->restoreState(state);
895 QModelIndex currentIndex;
899 m_ui->contentTreeView->setExpanded(currentIndex,
true);
908 switch (downloadResult.
status)
916 .arg(downloadResult.
url, result.error()));
937 tr(
"Cannot download '%1': %2").arg(downloadResult.
url, downloadResult.
errorString));
947 m_ui->groupBoxSavePath->setEnabled(
true);
953 m_ui->groupBoxSavePath->setEnabled(
false);
955 m_ui->savePath->blockSignals(
true);
956 m_ui->savePath->clear();
957 const QString savePath = session->categorySavePath(
m_ui->categoryComboBox->currentText());
958 m_ui->savePath->addItem(savePath);
960 m_ui->downloadPath->blockSignals(
true);
961 m_ui->downloadPath->clear();
962 const QString downloadPath = session->categoryDownloadPath(
m_ui->categoryComboBox->currentText());
963 m_ui->downloadPath->addItem(downloadPath);
965 m_ui->groupBoxDownloadPath->blockSignals(
true);
966 m_ui->groupBoxDownloadPath->setChecked(!downloadPath.isEmpty());
982 m_ui->contentTreeView->renameSelectedFile(fileStorageAdaptor);
QBITTORRENT_HAS_EXECINFO_H if(NOT QBITTORRENT_HAS_EXECINFO_H) message(FATAL_ERROR "execinfo.h header file not found.\n" "Please either disable the STACKTRACE feature or use a libc that has this header file
#define SETTINGS_KEY(name)
~AddNewTorrentDialog() override
static void setSavePathHistoryLength(int value)
void showEvent(QShowEvent *event) override
void onDownloadPathChanged(const QString &newPath)
bool loadTorrentFile(const QString &torrentPath)
AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri)
static const int minPathHistoryLength
void doNotDeleteTorrentClicked(bool checked)
void categoryChanged(int index)
static void setEnabled(bool value)
BitTorrent::MagnetUri m_magnetURI
BitTorrent::AddTorrentParams m_torrentParams
SettingValue< QSize > m_storeDialogSize
TorrentContentFilterModel * m_contentModel
void setMetadataProgressIndicator(bool visibleIndicator, const QString &labelText={})
void contentLayoutChanged(int index)
static void show(const QString &source, const BitTorrent::AddTorrentParams &inParams, QWidget *parent)
SettingValue< QByteArray > m_storeTreeHeaderState
void displayContentTreeMenu(const QPoint &)
SettingValue< bool > m_storeRememberLastSavePath
static const int maxPathHistoryLength
void updateMetadata(const BitTorrent::TorrentInfo &metadata)
void TMMChanged(int index)
static int savePathHistoryLength()
void onUseDownloadPathChanged(bool checked)
static void setTopLevel(bool value)
Ui::AddNewTorrentDialog * m_ui
void onSavePathChanged(const QString &newPath)
SettingValue< QString > m_storeDefaultCategory
void updateDiskSpaceLabel()
void handleDownloadFinished(const Net::DownloadResult &downloadResult)
void renameSelectedFile()
PropListDelegate * m_contentDelegate
std::unique_ptr< TorrentFileGuard > m_torrentGuard
SettingValue< QByteArray > m_storeSplitterState
BitTorrent::TorrentInfo m_torrentInfo
TorrentID toTorrentID() const
QVector< TrackerEntry > trackers() const
InfoHash infoHash() const
QVector< QUrl > urlSeeds() const
bool cancelDownloadMetadata(const TorrentID &id)
static Session * instance()
void metadataDownloaded(const TorrentInfo &info)
bool addTorrent(const QString &source, const AddTorrentParams ¶ms=AddTorrentParams())
bool downloadMetadata(const MagnetUri &magnetUri)
Torrent * findTorrent(const TorrentID &id) const
virtual void addUrlSeeds(const QVector< QUrl > &urlSeeds)=0
virtual void addTrackers(const QVector< TrackerEntry > &trackers)=0
virtual bool isPrivate() const =0
virtual QString name() const =0
static TorrentID fromInfoHash(const InfoHash &infoHash)
QVector< QUrl > urlSeeds() const
static nonstd::expected< TorrentInfo, QString > load(const QByteArray &data) noexcept
qlonglong totalSize() const
QVector< TrackerEntry > trackers() const
InfoHash infoHash() const
QStringList filePaths() const
QDateTime creationDate() const
qlonglong fileSize(int index) const
nonstd::expected< void, QString > saveToFile(const QString &path) const
static nonstd::expected< TorrentInfo, QString > loadFromFile(const QString &path) noexcept
Widget which uses QComboBox for path editing.
QString item(int index) const
void insertItem(int index, const QString &text)
void setCurrentIndex(int index)
@ DirectorySave
selecting directories for saving
void selectedPathChanged(const QString &path)
static bool hasSupportedScheme(const QString &url)
DownloadHandler * download(const DownloadRequest &downloadRequest)
static DownloadManager * instance()
static QMessageBox::StandardButton information(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton defaultButton=QMessageBox::NoButton)
static QMessageBox::StandardButton critical(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton defaultButton=QMessageBox::NoButton)
static QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton defaultButton=QMessageBox::NoButton)
void storeValue(const QString &key, const T &value)
T loadValue(const QString &key, const T &defaultValue={}) const
static SettingsStorage * instance()
TorrentContentModel * model() const
void updateFilesPriorities(const QVector< BitTorrent::DownloadPriority > &fprio)
QVector< BitTorrent::DownloadPriority > getFilePriorities() const
void filteredFilesChanged()
void setupModelData(const BitTorrent::AbstractFileStorage &info)
static AutoDeleteMode autoDeleteMode()
static UIThemeManager * instance()
const BitTorrent::TorrentInfo & m_torrentInfo
FileStorageAdaptor(const BitTorrent::TorrentInfo &torrentInfo, QStringList &filePaths)
void renameFile(const int index, const QString &newFilePath) override
int filesCount() const override
QStringList & m_filePaths
QString filePath(const int index) const override
qlonglong fileSize(const int index) const override
const char C_TORRENT_FILE_EXTENSION[]
const int MAX_TORRENT_SIZE
constexpr std::add_const_t< T > & asConst(T &t) noexcept
TorrentContentLayout detectContentLayout(const QStringList &filePaths)
void applyContentLayout(QStringList &filePaths, TorrentContentLayout contentLayout, const QString &rootFolder={})
qint64 freeDiskSpaceOnPath(const QString &path)
QString findRootFolder(const QStringList &filePaths)
QString toNativePath(const QString &path)
void resize(QWidget *widget, const QSize &newSize={})
QString parseHtmlLinks(const QString &rawText)
QString friendlyUnit(qint64 bytes, bool isSpeed=false)
const QString KEY_ENABLED
const QString KEY_TOPLEVEL
int indexOfPath(const FileSystemPathComboEdit *fsPathEdit, const QString &savePath)
void updatePathHistory(const QString &settingsKey, const QString &path, const int maxLength)
SettingsStorage * settings()
const QString KEY_DOWNLOADPATHHISTORY
const QString KEY_SAVEPATHHISTORYLENGTH
const QString KEY_SAVEPATHHISTORY
void setPath(FileSystemPathComboEdit *fsPathEdit, const QString &newPath)
T value(const QString &key, const T &defaultValue={})
QString toString(const lt::socket_type_t socketType)
QVector< DownloadPriority > filePriorities
std::optional< bool > useDownloadPath
bool firstLastPiecePriority
std::optional< bool > useAutoTMM
std::optional< bool > addPaused
std::optional< BitTorrent::TorrentContentLayout > contentLayout