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

This commit is contained in:
Christophe Dumez 2010-01-01 10:55:13 +00:00
parent 533e402bca
commit add2475700
5 changed files with 248 additions and 97 deletions

View file

@ -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)

View file

@ -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

View file

@ -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;
} }

View file

@ -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);
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));
// 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 { } else {
// Available disk space is unknown
label_space_msg->setText("");
}
}
void on_browseButton_clicked(){
QString dir;
QString save_path = misc::expandPath(savePathTxt->text());
QDir saveDir(save_path);
if(!save_path.isEmpty() && saveDir.exists()){
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath());
}else{
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
}
if(!dir.isNull()){
savePathTxt->setText(dir);
}
}
void on_CancelButton_clicked(){
close();
}
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; return;
} }
QDir savePath(misc::expandPath(savePathTxt->text())); // Call menu
// Check if savePath exists QAction *act = myFilesLlistMenu.exec(QCursor::pos());
if(!savePath.exists()){ if(act) {
if(!savePath.mkpath(savePath.path())){ if(act == actRename) {
QMessageBox::critical(0, tr("Save path creation error"), tr("Could not create the save path")); renameSelectedFile();
return;
} }
} }
// Save savepath }
TorrentTempData::setSavePath(hash, savePath.path());
qDebug("Torrent label is: %s", comboLabel->currentText().trimmed().toLocal8Bit().data()); void renameSelectedFile() {
TorrentTempData::setLabel(hash, comboLabel->currentText().trimmed()); QModelIndexList selectedIndexes = torrentContentList->selectionModel()->selectedRows(0);
// Is download sequential? Q_ASSERT(selectedIndexes.size() == 1);
TorrentTempData::setSequential(hash, checkIncrementalDL->isChecked()); QModelIndex index = selectedIndexes.first();
// Ask for new name
bool ok;
QString new_name_last = QInputDialog::getText(this, tr("Rename torrent file"),
tr("New name:"), QLineEdit::Normal,
index.data().toString(), &ok);
if (ok && !new_name_last.isEmpty()) {
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 updateDiskSpaceLabels() {
long long available = misc::freeDiskSpaceOnPath(misc::expandPath(savePathTxt->text()));
lbl_disk_space->setText(misc::friendlyUnit(available));
// Determine torrent size
qulonglong torrent_size = 0;
unsigned int nbFiles = t->num_files();
std::vector<int> priorities = PropListModel->getFilesPriorities(nbFiles);
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));
// 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_browseButton_clicked(){
QString dir;
QString save_path = misc::expandPath(savePathTxt->text());
QDir saveDir(save_path);
if(!save_path.isEmpty() && saveDir.exists()){
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath());
}else{
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
}
if(!dir.isNull()){
savePathTxt->setText(dir);
}
}
void on_CancelButton_clicked(){
close();
}
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
path_changed = true;
break;
}
}
if(path_changed) {
TorrentTempData::setFilesPath(hash, files_path);
}
#ifdef LIBTORRENT_0_15 #ifdef LIBTORRENT_0_15
// Skip file checking and directly start seeding // Skip file checking and directly start seeding
if(addInSeed->isChecked()) { if(addInSeed->isChecked()) {
// Check if local file(s) actually exist // Check if local file(s) actually exist
if(savePath.exists(misc::toQString(t->name()))) { if(savePath.exists(misc::toQString(t->name()))) {
TorrentTempData::setSeedingMode(hash, true); TorrentTempData::setSeedingMode(hash, true);
} else { } 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.")); 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; return;
} }
} }
#endif #endif
// Check if there is at least one selected file // Check if there is at least one selected file
if(allFiltered()){ if(allFiltered()){
QMessageBox::warning(0, tr("Invalid file selection"), tr("You must select at least one file in the torrent")); QMessageBox::warning(0, tr("Invalid file selection"), tr("You must select at least one file in the torrent"));
return; return;
} }
// save filtered files // save filtered files
savePiecesPriorities(); savePiecesPriorities();
// Add to download list // Add to download list
QTorrentHandle h = BTSession->addTorrent(filePath, false, from_url); QTorrentHandle h = BTSession->addTorrent(filePath, false, from_url);
if(addInPause->isChecked() && h.is_valid()) if(addInPause->isChecked() && h.is_valid())
h.pause(); h.pause();
close(); close();
} }
}; };
#endif #endif

View file

@ -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();