diff --git a/Changelog b/Changelog index b136d3879..389693f83 100644 --- a/Changelog +++ b/Changelog @@ -4,7 +4,7 @@ - FEATURE: Disk cache size can be set from preferences - FEATURE: Peer Exchange (PeX) can be disabled from preferences - 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: Better proxy support and preferences remodeling - FEATURE: qBittorrent can identify itself as uTorrent or Vuze (Any version) diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index 061b723b1..8adc582f7 100644 --- a/src/bittorrent.cpp +++ b/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)"); h.prioritize_files(TorrentTempData::getFilesPriority(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 #include #include +#include #include #include @@ -67,6 +68,7 @@ private: PropListDelegate *PropDelegate; unsigned int nbFiles; boost::intrusive_ptr t; + QStringList files_path; public: torrentAdditionDialog(QWidget *parent, Bittorrent* _BTSession) : QDialog(parent) { @@ -80,6 +82,7 @@ public: PropDelegate = new PropListDelegate(); torrentContentList->setItemDelegate(PropDelegate); 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(expandAllButton, SIGNAL(clicked()), torrentContentList, SLOT(expandAll())); // Remember columns width @@ -194,113 +197,235 @@ public: foreach(const QString& label, customLabels) { comboLabel->addItem(label); } + // Loads files path in the torrent + for(uint i=0; ifile_at(i).path.string()); + } // Show the dialog show(); } public slots: - 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 priorities = PropListModel->getFilesPriorities(nbFiles); - - for(unsigned int i=0; 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(""+tr("(%1 more are required to download)", "e.g. (100MiB more are required to download)").arg(misc::friendlyUnit(torrent_size-available))+""); - } + void displayContentListMenu(const QPoint&) { + QMenu myFilesLlistMenu; + QModelIndexList selectedRows = torrentContentList->selectionModel()->selectedRows(0); + QAction *actRename = 0; + if(selectedRows.size() == 1) { + actRename = myFilesLlistMenu.addAction(QIcon(QString::fromUtf8(":/Icons/oxygen/edit_clear.png")), tr("Rename...")); + //myFilesLlistMenu.addSeparator(); } 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 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; + // Call menu + QAction *act = myFilesLlistMenu.exec(QCursor::pos()); + if(act) { + if(act == actRename) { + renameSelectedFile(); } } - // 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()); + } + + void renameSelectedFile() { + QModelIndexList selectedIndexes = torrentContentList->selectionModel()->selectedRows(0); + Q_ASSERT(selectedIndexes.size() == 1); + 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; isetData(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; isetData(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 priorities = PropListModel->getFilesPriorities(nbFiles); + + for(unsigned int i=0; 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(""+tr("(%1 more are required to download)", "e.g. (100MiB more are required to download)").arg(misc::friendlyUnit(torrent_size-available))+""); + } + } 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 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; ifile_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 - // 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; - } - } + // 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; + } + } #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(); - } -}; + // 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 diff --git a/src/torrentpersistentdata.h b/src/torrentpersistentdata.h index 45f537dae..dd7a0dfae 100644 --- a/src/torrentpersistentdata.h +++ b/src/torrentpersistentdata.h @@ -78,6 +78,15 @@ public: settings.setValue("torrents-tmp", all_data); } + static void setFilesPath(QString hash, QStringList path_list) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash 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) { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); @@ -146,6 +155,15 @@ public: return QString::null; } + static QStringList getFilesPath(QString hash) { + QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); + QHash all_data = settings.value("torrents-tmp", QHash()).toHash(); + QHash data = all_data[hash].toHash(); + if(data.contains("files_path")) + return data["files_path"].toStringList(); + return QStringList(); + } + static QString getLabel(QString hash) { QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QHash all_data = settings.value("torrents-tmp", QHash()).toHash();