Browse Source

- Files / Folders can also be renamed directly from torrent addition dialog

adaptive-webui-19844
Christophe Dumez 15 years ago
parent
commit
add2475700
  1. 2
      Changelog
  2. 8
      src/bittorrent.cpp
  3. 2
      src/propertieswidget.cpp
  4. 305
      src/torrentadditiondlg.h
  5. 18
      src/torrentpersistentdata.h

2
Changelog

@ -4,7 +4,7 @@
- FEATURE: Disk cache size can be set from preferences - FEATURE: Disk cache size can be set from preferences
- FEATURE: Peer Exchange (PeX) can be disabled from preferences - FEATURE: Peer Exchange (PeX) can be disabled from preferences
- FEATURE: Append !.qB extension to incomplete files option (libtorrent >= v0.15 only) - FEATURE: Append !.qB extension to incomplete files option (libtorrent >= v0.15 only)
- FEATURE: Torrent files/folders can be renamed - FEATURE: Torrent files/folders can be renamed (torrent addition dialog or files properties)
- FEATURE: uTorrent compatible tracker list support (use torrentz.com url as a default) - FEATURE: uTorrent compatible tracker list support (use torrentz.com url as a default)
- FEATURE: Better proxy support and preferences remodeling - FEATURE: Better proxy support and preferences remodeling
- FEATURE: qBittorrent can identify itself as uTorrent or Vuze (Any version) - FEATURE: qBittorrent can identify itself as uTorrent or Vuze (Any version)

8
src/bittorrent.cpp

@ -960,6 +960,14 @@ QTorrentHandle Bittorrent::addTorrent(QString path, bool fromScanDir, QString fr
qDebug("addTorrent: Setting download as sequential (from tmp data)"); qDebug("addTorrent: Setting download as sequential (from tmp data)");
h.prioritize_files(TorrentTempData::getFilesPriority(hash)); h.prioritize_files(TorrentTempData::getFilesPriority(hash));
h.set_sequential_download(TorrentTempData::isSequential(hash)); h.set_sequential_download(TorrentTempData::isSequential(hash));
// Import Files names from torrent addition dialog
QStringList files_path = TorrentTempData::getFilesPath(hash);
if(files_path.size() == h.num_files()) {
for(int i=0; i<h.num_files(); ++i) {
QString path = files_path.at(i);
h.rename_file(i, path);
}
}
} }
QString label = TorrentTempData::getLabel(hash); QString label = TorrentTempData::getLabel(hash);
// Save persistent data for new torrent // Save persistent data for new torrent

2
src/propertieswidget.cpp

@ -467,7 +467,7 @@ void PropertiesWidget::displayFilesListMenu(const QPoint&){
QAction *actRename = 0; QAction *actRename = 0;
if(selectedRows.size() == 1) { if(selectedRows.size() == 1) {
actRename = myFilesLlistMenu.addAction(QIcon(QString::fromUtf8(":/Icons/oxygen/edit_clear.png")), tr("Rename...")); actRename = myFilesLlistMenu.addAction(QIcon(QString::fromUtf8(":/Icons/oxygen/edit_clear.png")), tr("Rename..."));
myFilesLlistMenu.addSeparator(); //myFilesLlistMenu.addSeparator();
} else { } else {
return; return;
} }

305
src/torrentadditiondlg.h

@ -41,6 +41,7 @@
#include <QHeaderView> #include <QHeaderView>
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QInputDialog>
#include <libtorrent/session.hpp> #include <libtorrent/session.hpp>
#include <libtorrent/bencode.hpp> #include <libtorrent/bencode.hpp>
@ -67,6 +68,7 @@ private:
PropListDelegate *PropDelegate; PropListDelegate *PropDelegate;
unsigned int nbFiles; unsigned int nbFiles;
boost::intrusive_ptr<torrent_info> t; boost::intrusive_ptr<torrent_info> t;
QStringList files_path;
public: public:
torrentAdditionDialog(QWidget *parent, Bittorrent* _BTSession) : QDialog(parent) { torrentAdditionDialog(QWidget *parent, Bittorrent* _BTSession) : QDialog(parent) {
@ -80,6 +82,7 @@ public:
PropDelegate = new PropListDelegate(); PropDelegate = new PropListDelegate();
torrentContentList->setItemDelegate(PropDelegate); torrentContentList->setItemDelegate(PropDelegate);
connect(torrentContentList, SIGNAL(clicked(const QModelIndex&)), torrentContentList, SLOT(edit(const QModelIndex&))); connect(torrentContentList, SIGNAL(clicked(const QModelIndex&)), torrentContentList, SLOT(edit(const QModelIndex&)));
connect(torrentContentList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayContentListMenu(const QPoint&)));
connect(collapseAllButton, SIGNAL(clicked()), torrentContentList, SLOT(collapseAll())); connect(collapseAllButton, SIGNAL(clicked()), torrentContentList, SLOT(collapseAll()));
connect(expandAllButton, SIGNAL(clicked()), torrentContentList, SLOT(expandAll())); connect(expandAllButton, SIGNAL(clicked()), torrentContentList, SLOT(expandAll()));
// Remember columns width // Remember columns width
@ -194,113 +197,235 @@ public:
foreach(const QString& label, customLabels) { foreach(const QString& label, customLabels) {
comboLabel->addItem(label); comboLabel->addItem(label);
} }
// Loads files path in the torrent
for(uint i=0; i<nbFiles; ++i) {
files_path << misc::toQString(t->file_at(i).path.string());
}
// Show the dialog // Show the dialog
show(); show();
} }
public slots: public slots:
void updateDiskSpaceLabels() { void displayContentListMenu(const QPoint&) {
long long available = misc::freeDiskSpaceOnPath(misc::expandPath(savePathTxt->text())); QMenu myFilesLlistMenu;
lbl_disk_space->setText(misc::friendlyUnit(available)); QModelIndexList selectedRows = torrentContentList->selectionModel()->selectedRows(0);
QAction *actRename = 0;
// Determine torrent size if(selectedRows.size() == 1) {
qulonglong torrent_size = 0; actRename = myFilesLlistMenu.addAction(QIcon(QString::fromUtf8(":/Icons/oxygen/edit_clear.png")), tr("Rename..."));
unsigned int nbFiles = t->num_files(); //myFilesLlistMenu.addSeparator();
std::vector<int> priorities = PropListModel->getFilesPriorities(nbFiles); } else {
return;
for(unsigned int i=0; i<nbFiles; ++i) {
if(priorities[i] > 0)
torrent_size += t->file_at(i).size;
} }
lbl_torrent_size->setText(misc::friendlyUnit(torrent_size)); // Call menu
// Check if free space is sufficient QAction *act = myFilesLlistMenu.exec(QCursor::pos());
if(available > 0) { if(act) {
if((unsigned long long)available > torrent_size) { if(act == actRename) {
// Space is sufficient renameSelectedFile();
label_space_msg->setText(tr("(%1 left after torrent download)", "e.g. (100MiB left after torrent download)").arg(misc::friendlyUnit(available-torrent_size)));
} else {
// Space is unsufficient
label_space_msg->setText("<font color=\"red\">"+tr("(%1 more are required to download)", "e.g. (100MiB more are required to download)").arg(misc::friendlyUnit(torrent_size-available))+"</font>");
} }
} else {
// Available disk space is unknown
label_space_msg->setText("");
} }
} }
void on_browseButton_clicked(){ void renameSelectedFile() {
QString dir; QModelIndexList selectedIndexes = torrentContentList->selectionModel()->selectedRows(0);
QString save_path = misc::expandPath(savePathTxt->text()); Q_ASSERT(selectedIndexes.size() == 1);
QDir saveDir(save_path); QModelIndex index = selectedIndexes.first();
if(!save_path.isEmpty() && saveDir.exists()){ // Ask for new name
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath()); bool ok;
}else{ QString new_name_last = QInputDialog::getText(this, tr("Rename torrent file"),
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath()); tr("New name:"), QLineEdit::Normal,
} index.data().toString(), &ok);
if(!dir.isNull()){ if (ok && !new_name_last.isEmpty()) {
savePathTxt->setText(dir); if(PropListModel->getType(index)==TFILE) {
} // File renaming
} uint file_index = PropListModel->getFileIndex(index);
QString old_name = files_path.at(file_index);
QStringList path_items = old_name.split(QDir::separator());
path_items.removeLast();
path_items << new_name_last;
QString new_name = path_items.join(QDir::separator());
if(old_name == new_name) {
qDebug("Name did not change");
return;
}
// Check if that name is already used
for(uint i=0; i<nbFiles; ++i) {
if(i == file_index) continue;
#ifdef Q_WS_WIN
if(files_path.at(i).compare(new_name, Qt::CaseInsensitive) == 0) {
#else
if(files_path.at(i).compare(new_name, Qt::CaseSensitive) == 0) {
#endif
// Display error message
QMessageBox::warning(this, tr("The file could not be renamed"),
tr("This name is already in use in this folder. Please use a different name."),
QMessageBox::Ok);
return;
}
}
qDebug("Renaming %s to %s", old_name.toLocal8Bit().data(), new_name.toLocal8Bit().data());
// Rename file in files_path
files_path.replace(file_index, new_name);
// Rename in torrent files model too
PropListModel->setData(index, new_name_last);
} else {
// Folder renaming
QStringList path_items;
path_items << index.data().toString();
QModelIndex parent = PropListModel->parent(index);
while(parent.isValid()) {
path_items.prepend(parent.data().toString());
parent = PropListModel->parent(parent);
}
QString old_path = path_items.join(QDir::separator());
path_items.removeLast();
path_items << new_name_last;
QString new_path = path_items.join(QDir::separator());
// Check for overwriting
for(uint i=0; i<nbFiles; ++i) {
QString current_name = files_path.at(i);
#ifdef Q_WS_WIN
if(current_name.contains(new_path, Qt::CaseInsensitive)) {
#else
if(current_name.contains(new_path, Qt::CaseSensitive)) {
#endif
QMessageBox::warning(this, tr("The folder could not be renamed"),
tr("This name is already in use in this folder. Please use a different name."),
QMessageBox::Ok);
return;
}
}
// Replace path in all files
for(uint i=0; i<nbFiles; ++i) {
QString current_name = files_path.at(i);
QString new_name = current_name.replace(old_path, new_path);
qDebug("Rename %s to %s", current_name.toLocal8Bit().data(), new_name.toLocal8Bit().data());
// Rename in files_path
files_path.replace(i, new_name);
}
// Rename folder in torrent files model too
PropListModel->setData(index, new_name_last);
}
}
}
void on_CancelButton_clicked(){ void updateDiskSpaceLabels() {
close(); long long available = misc::freeDiskSpaceOnPath(misc::expandPath(savePathTxt->text()));
} lbl_disk_space->setText(misc::friendlyUnit(available));
bool allFiltered() const { // Determine torrent size
return PropListModel->allFiltered(); qulonglong torrent_size = 0;
} unsigned int nbFiles = t->num_files();
std::vector<int> priorities = PropListModel->getFilesPriorities(nbFiles);
void savePiecesPriorities(){ for(unsigned int i=0; i<nbFiles; ++i) {
qDebug("Saving pieces priorities"); if(priorities[i] > 0)
std::vector<int> priorities = PropListModel->getFilesPriorities(t->num_files()); torrent_size += t->file_at(i).size;
TorrentTempData::setFilesPriority(hash, priorities); }
} lbl_torrent_size->setText(misc::friendlyUnit(torrent_size));
// Check if free space is sufficient
if(available > 0) {
if((unsigned long long)available > torrent_size) {
// Space is sufficient
label_space_msg->setText(tr("(%1 left after torrent download)", "e.g. (100MiB left after torrent download)").arg(misc::friendlyUnit(available-torrent_size)));
} else {
// Space is unsufficient
label_space_msg->setText("<font color=\"red\">"+tr("(%1 more are required to download)", "e.g. (100MiB more are required to download)").arg(misc::friendlyUnit(torrent_size-available))+"</font>");
}
} else {
// Available disk space is unknown
label_space_msg->setText("");
}
}
void on_OkButton_clicked(){ void on_browseButton_clicked(){
if(savePathTxt->text().trimmed().isEmpty()){ QString dir;
QMessageBox::critical(0, tr("Empty save path"), tr("Please enter a save path")); QString save_path = misc::expandPath(savePathTxt->text());
return; QDir saveDir(save_path);
} if(!save_path.isEmpty() && saveDir.exists()){
QDir savePath(misc::expandPath(savePathTxt->text())); dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath());
// Check if savePath exists }else{
if(!savePath.exists()){ dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
if(!savePath.mkpath(savePath.path())){ }
QMessageBox::critical(0, tr("Save path creation error"), tr("Could not create the save path")); if(!dir.isNull()){
return; savePathTxt->setText(dir);
}
} }
}
// Save savepath void on_CancelButton_clicked(){
TorrentTempData::setSavePath(hash, savePath.path()); close();
qDebug("Torrent label is: %s", comboLabel->currentText().trimmed().toLocal8Bit().data());
TorrentTempData::setLabel(hash, comboLabel->currentText().trimmed());
// Is download sequential?
TorrentTempData::setSequential(hash, checkIncrementalDL->isChecked());
#ifdef LIBTORRENT_0_15
// Skip file checking and directly start seeding
if(addInSeed->isChecked()) {
// Check if local file(s) actually exist
if(savePath.exists(misc::toQString(t->name()))) {
TorrentTempData::setSeedingMode(hash, true);
} else {
QMessageBox::warning(0, tr("Seeding mode error"), tr("You chose to skip file checking. However, local files do not seem to exist in the current destionation folder. Please disable this feature or update the save path."));
return;
} }
}
bool allFiltered() const {
return PropListModel->allFiltered();
}
void savePiecesPriorities(){
qDebug("Saving pieces priorities");
std::vector<int> priorities = PropListModel->getFilesPriorities(t->num_files());
TorrentTempData::setFilesPriority(hash, priorities);
}
void on_OkButton_clicked(){
if(savePathTxt->text().trimmed().isEmpty()){
QMessageBox::critical(0, tr("Empty save path"), tr("Please enter a save path"));
return;
}
QDir savePath(misc::expandPath(savePathTxt->text()));
// Check if savePath exists
if(!savePath.exists()){
if(!savePath.mkpath(savePath.path())){
QMessageBox::critical(0, tr("Save path creation error"), tr("Could not create the save path"));
return;
}
}
// Save savepath
TorrentTempData::setSavePath(hash, savePath.path());
qDebug("Torrent label is: %s", comboLabel->currentText().trimmed().toLocal8Bit().data());
TorrentTempData::setLabel(hash, comboLabel->currentText().trimmed());
// Is download sequential?
TorrentTempData::setSequential(hash, checkIncrementalDL->isChecked());
// Save files path
// Loads files path in the torrent
bool path_changed = false;
for(uint i=0; i<nbFiles; ++i) {
#ifdef Q_WS_WIN
if(files_path.at(i).compare(misc::toQString(t->file_at(i).path.string()), Qt::CaseInsensitive) != 0) {
#else
if(files_path.at(i).compare(misc::toQString(t->file_at(i).path.string()), Qt::CaseSensitive) != 0) {
#endif #endif
// Check if there is at least one selected file path_changed = true;
if(allFiltered()){ break;
QMessageBox::warning(0, tr("Invalid file selection"), tr("You must select at least one file in the torrent")); }
return; }
} if(path_changed) {
// save filtered files TorrentTempData::setFilesPath(hash, files_path);
savePiecesPriorities(); }
// Add to download list #ifdef LIBTORRENT_0_15
QTorrentHandle h = BTSession->addTorrent(filePath, false, from_url); // Skip file checking and directly start seeding
if(addInPause->isChecked() && h.is_valid()) if(addInSeed->isChecked()) {
h.pause(); // Check if local file(s) actually exist
close(); if(savePath.exists(misc::toQString(t->name()))) {
} TorrentTempData::setSeedingMode(hash, true);
}; } else {
QMessageBox::warning(0, tr("Seeding mode error"), tr("You chose to skip file checking. However, local files do not seem to exist in the current destionation folder. Please disable this feature or update the save path."));
return;
}
}
#endif
// Check if there is at least one selected file
if(allFiltered()){
QMessageBox::warning(0, tr("Invalid file selection"), tr("You must select at least one file in the torrent"));
return;
}
// save filtered files
savePiecesPriorities();
// Add to download list
QTorrentHandle h = BTSession->addTorrent(filePath, false, from_url);
if(addInPause->isChecked() && h.is_valid())
h.pause();
close();
}
};
#endif #endif

18
src/torrentpersistentdata.h

@ -78,6 +78,15 @@ public:
settings.setValue("torrents-tmp", all_data); settings.setValue("torrents-tmp", all_data);
} }
static void setFilesPath(QString hash, QStringList path_list) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
data["files_path"] = path_list;
all_data[hash] = data;
settings.setValue("torrents-tmp", all_data);
}
static void setSavePath(QString hash, QString save_path) { static void setSavePath(QString hash, QString save_path) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash(); QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
@ -146,6 +155,15 @@ public:
return QString::null; return QString::null;
} }
static QStringList getFilesPath(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();
QHash<QString, QVariant> data = all_data[hash].toHash();
if(data.contains("files_path"))
return data["files_path"].toStringList();
return QStringList();
}
static QString getLabel(QString hash) { static QString getLabel(QString hash) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume"));
QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash(); QHash<QString, QVariant> all_data = settings.value("torrents-tmp", QHash<QString, QVariant>()).toHash();

Loading…
Cancel
Save