From 62ccfd37b23c33e62bc1fd276c420f5d31c07442 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Tue, 4 Jun 2019 14:00:42 +0800 Subject: [PATCH 1/4] Move renameSelectedFile(BitTorrent::TorrentHandle *) --- src/gui/properties/propertieswidget.cpp | 124 +--------------------- src/gui/properties/propertieswidget.h | 1 - src/gui/torrentcontenttreeview.cpp | 133 ++++++++++++++++++++++++ src/gui/torrentcontenttreeview.h | 7 ++ 4 files changed, 143 insertions(+), 122 deletions(-) diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index 07209d963..2796740f8 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -150,7 +150,8 @@ PropertiesWidget::PropertiesWidget(QWidget *parent) connect(m_tabBar, &PropTabBar::visibilityToggled, this, &PropertiesWidget::saveSettings); m_editHotkeyFile = new QShortcut(Qt::Key_F2, m_ui->filesList, nullptr, nullptr, Qt::WidgetShortcut); - connect(m_editHotkeyFile, &QShortcut::activated, this, &PropertiesWidget::renameSelectedFile); + connect(m_editHotkeyFile, &QShortcut::activated + , this, [this]() { m_ui->filesList->renameSelectedFile(m_torrent); }); m_editHotkeyWeb = new QShortcut(Qt::Key_F2, m_ui->listWebSeeds, nullptr, nullptr, Qt::WidgetShortcut); connect(m_editHotkeyWeb, &QShortcut::activated, this, &PropertiesWidget::editWebSeed); connect(m_ui->listWebSeeds, &QListWidget::doubleClicked, this, &PropertiesWidget::editWebSeed); @@ -621,7 +622,7 @@ void PropertiesWidget::displayFilesListMenu(const QPoint &) openFolder(index, true); } else if (act == actRename) { - renameSelectedFile(); + m_ui->filesList->renameSelectedFile(m_torrent); } else { BitTorrent::DownloadPriority prio = BitTorrent::DownloadPriority::Normal; @@ -673,125 +674,6 @@ void PropertiesWidget::displayWebSeedListMenu(const QPoint &) editWebSeed(); } -void PropertiesWidget::renameSelectedFile() -{ - if (!m_torrent) return; - - const QModelIndexList selectedIndexes = m_ui->filesList->selectionModel()->selectedRows(0); - if (selectedIndexes.size() != 1) return; - - const QModelIndex modelIndex = selectedIndexes.first(); - if (!modelIndex.isValid()) return; - - // Ask for new name - bool ok = false; - const bool isFile = (m_propListModel->itemType(modelIndex) == TorrentContentModelItem::FileType); - QString newName = AutoExpandableDialog::getText(this, tr("Renaming"), tr("New name:"), QLineEdit::Normal - , modelIndex.data().toString(), &ok, isFile).trimmed(); - if (!ok) return; - - if (newName.isEmpty() || !Utils::Fs::isValidFileSystemName(newName)) { - RaisedMessageBox::warning(this, tr("Rename error"), - tr("The name is empty or contains forbidden characters, please choose a different one."), - QMessageBox::Ok); - return; - } - - if (isFile) { - const int fileIndex = m_propListModel->getFileIndex(modelIndex); - - if (newName.endsWith(QB_EXT)) - newName.chop(QB_EXT.size()); - const QString oldFileName = m_torrent->fileName(fileIndex); - const QString oldFilePath = m_torrent->filePath(fileIndex); - - const bool useFilenameExt = BitTorrent::Session::instance()->isAppendExtensionEnabled() - && (m_torrent->filesProgress()[fileIndex] != 1); - const QString newFileName = newName + (useFilenameExt ? QB_EXT : QString()); - const QString newFilePath = oldFilePath.leftRef(oldFilePath.size() - oldFileName.size()) + newFileName; - - if (oldFileName == newFileName) { - qDebug("Name did not change: %s", qUtf8Printable(oldFileName)); - return; - } - - // check if that name is already used - for (int i = 0; i < m_torrent->filesCount(); ++i) { - if (i == fileIndex) continue; - if (Utils::Fs::sameFileNames(m_torrent->filePath(i), newFilePath)) { - RaisedMessageBox::warning(this, tr("Rename error"), - tr("This name is already in use in this folder. Please use a different name."), - QMessageBox::Ok); - return; - } - } - - qDebug("Renaming %s to %s", qUtf8Printable(oldFilePath), qUtf8Printable(newFilePath)); - m_torrent->renameFile(fileIndex, newFilePath); - - m_propListModel->setData(modelIndex, newName); - } - else { - // renaming a folder - QStringList pathItems; - pathItems << modelIndex.data().toString(); - QModelIndex parent = m_propListModel->parent(modelIndex); - while (parent.isValid()) { - pathItems.prepend(parent.data().toString()); - parent = m_propListModel->parent(parent); - } - const QString oldPath = pathItems.join('/'); - pathItems.removeLast(); - pathItems << newName; - QString newPath = pathItems.join('/'); - if (Utils::Fs::sameFileNames(oldPath, newPath)) { - qDebug("Name did not change"); - return; - } - if (!newPath.endsWith('/')) newPath += '/'; - // Check for overwriting - for (int i = 0; i < m_torrent->filesCount(); ++i) { - const QString currentName = m_torrent->filePath(i); -#if defined(Q_OS_UNIX) || defined(Q_WS_QWS) - if (currentName.startsWith(newPath, Qt::CaseSensitive)) { -#else - if (currentName.startsWith(newPath, Qt::CaseInsensitive)) { -#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; - } - } - bool forceRecheck = false; - // Replace path in all files - for (int i = 0; i < m_torrent->filesCount(); ++i) { - const QString currentName = m_torrent->filePath(i); - if (currentName.startsWith(oldPath)) { - QString newName = currentName; - newName.replace(0, oldPath.length(), newPath); - if (!forceRecheck && QDir(m_torrent->savePath(true)).exists(newName)) - forceRecheck = true; - newName = Utils::Fs::expandPath(newName); - qDebug("Rename %s to %s", qUtf8Printable(currentName), qUtf8Printable(newName)); - m_torrent->renameFile(i, newName); - } - } - // Force recheck - if (forceRecheck) m_torrent->forceRecheck(); - // Rename folder in torrent files model too - m_propListModel->setData(modelIndex, newName); - // Remove old folder - const QDir oldFolder(m_torrent->savePath(true) + '/' + oldPath); - int timeout = 10; - while (!QDir().rmpath(oldFolder.absolutePath()) && (timeout > 0)) { - // FIXME: We should not sleep here (freezes the UI for 1 second) - QThread::msleep(100); - --timeout; - } - } -} - void PropertiesWidget::openSelectedFile() { const QModelIndexList selectedIndexes = m_ui->filesList->selectionModel()->selectedRows(0); diff --git a/src/gui/properties/propertieswidget.h b/src/gui/properties/propertieswidget.h index c0c5750d3..7d4265c55 100644 --- a/src/gui/properties/propertieswidget.h +++ b/src/gui/properties/propertieswidget.h @@ -95,7 +95,6 @@ protected slots: void filteredFilesChanged(); void showPiecesDownloaded(bool show); void showPiecesAvailability(bool show); - void renameSelectedFile(); void openSelectedFile(); private slots: diff --git a/src/gui/torrentcontenttreeview.cpp b/src/gui/torrentcontenttreeview.cpp index 712964a95..48a7c7a8e 100644 --- a/src/gui/torrentcontenttreeview.cpp +++ b/src/gui/torrentcontenttreeview.cpp @@ -28,11 +28,22 @@ #include "torrentcontenttreeview.h" +#include #include #include +#include +#include #include #include +#include +#include "base/bittorrent/session.h" +#include "base/bittorrent/torrenthandle.h" +#include "base/global.h" +#include "base/utils/fs.h" +#include "autoexpandabledialog.h" +#include "raisedmessagebox.h" +#include "torrentcontentfiltermodel.h" #include "torrentcontentmodelitem.h" TorrentContentTreeView::TorrentContentTreeView(QWidget *parent) @@ -75,6 +86,128 @@ void TorrentContentTreeView::keyPressEvent(QKeyEvent *event) } } +void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentHandle *torrent) +{ + if (!torrent) return; + + const QModelIndexList selectedIndexes = selectionModel()->selectedRows(0); + if (selectedIndexes.size() != 1) return; + + const QModelIndex modelIndex = selectedIndexes.first(); + if (!modelIndex.isValid()) return; + + auto model = dynamic_cast(TorrentContentTreeView::model()); + if (!model) return; + + // Ask for new name + bool ok = false; + const bool isFile = (model->itemType(modelIndex) == TorrentContentModelItem::FileType); + QString newName = AutoExpandableDialog::getText(this, tr("Renaming"), tr("New name:"), QLineEdit::Normal + , modelIndex.data().toString(), &ok, isFile).trimmed(); + if (!ok) return; + + if (newName.isEmpty() || !Utils::Fs::isValidFileSystemName(newName)) { + RaisedMessageBox::warning(this, tr("Rename error"), + tr("The name is empty or contains forbidden characters, please choose a different one."), + QMessageBox::Ok); + return; + } + + if (isFile) { + const int fileIndex = model->getFileIndex(modelIndex); + + if (newName.endsWith(QB_EXT)) + newName.chop(QB_EXT.size()); + const QString oldFileName = torrent->fileName(fileIndex); + const QString oldFilePath = torrent->filePath(fileIndex); + + const bool useFilenameExt = BitTorrent::Session::instance()->isAppendExtensionEnabled() + && (torrent->filesProgress()[fileIndex] != 1); + const QString newFileName = newName + (useFilenameExt ? QB_EXT : QString()); + const QString newFilePath = oldFilePath.leftRef(oldFilePath.size() - oldFileName.size()) + newFileName; + + if (oldFileName == newFileName) { + qDebug("Name did not change: %s", qUtf8Printable(oldFileName)); + return; + } + + // check if that name is already used + for (int i = 0; i < torrent->filesCount(); ++i) { + if (i == fileIndex) continue; + if (Utils::Fs::sameFileNames(torrent->filePath(i), newFilePath)) { + RaisedMessageBox::warning(this, tr("Rename error"), + tr("This name is already in use in this folder. Please use a different name."), + QMessageBox::Ok); + return; + } + } + + qDebug("Renaming %s to %s", qUtf8Printable(oldFilePath), qUtf8Printable(newFilePath)); + torrent->renameFile(fileIndex, newFilePath); + + model->setData(modelIndex, newName); + } + else { + // renaming a folder + QStringList pathItems; + pathItems << modelIndex.data().toString(); + QModelIndex parent = model->parent(modelIndex); + while (parent.isValid()) { + pathItems.prepend(parent.data().toString()); + parent = model->parent(parent); + } + const QString oldPath = pathItems.join('/'); + pathItems.removeLast(); + pathItems << newName; + QString newPath = pathItems.join('/'); + if (Utils::Fs::sameFileNames(oldPath, newPath)) { + qDebug("Name did not change"); + return; + } + if (!newPath.endsWith('/')) newPath += '/'; + // Check for overwriting + for (int i = 0; i < torrent->filesCount(); ++i) { + const QString currentName = torrent->filePath(i); +#if defined(Q_OS_UNIX) || defined(Q_WS_QWS) + if (currentName.startsWith(newPath, Qt::CaseSensitive)) { +#else + if (currentName.startsWith(newPath, Qt::CaseInsensitive)) { +#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; + } + } + bool forceRecheck = false; + // Replace path in all files + for (int i = 0; i < torrent->filesCount(); ++i) { + const QString currentName = torrent->filePath(i); + if (currentName.startsWith(oldPath)) { + QString newName = currentName; + newName.replace(0, oldPath.length(), newPath); + if (!forceRecheck && QDir(torrent->savePath(true)).exists(newName)) + forceRecheck = true; + newName = Utils::Fs::expandPath(newName); + qDebug("Rename %s to %s", qUtf8Printable(currentName), qUtf8Printable(newName)); + torrent->renameFile(i, newName); + } + } + // Force recheck + if (forceRecheck) torrent->forceRecheck(); + // Rename folder in torrent files model too + model->setData(modelIndex, newName); + // Remove old folder + const QDir oldFolder(torrent->savePath(true) + '/' + oldPath); + int timeout = 10; + while (!QDir().rmpath(oldFolder.absolutePath()) && (timeout > 0)) { + // FIXME: We should not sleep here (freezes the UI for 1 second) + QThread::msleep(100); + --timeout; + } + } +} + QModelIndex TorrentContentTreeView::currentNameCell() { QModelIndex current = currentIndex(); diff --git a/src/gui/torrentcontenttreeview.h b/src/gui/torrentcontenttreeview.h index 62c1d4471..d2d75e25a 100644 --- a/src/gui/torrentcontenttreeview.h +++ b/src/gui/torrentcontenttreeview.h @@ -31,6 +31,11 @@ #include +namespace BitTorrent +{ + class TorrentHandle; +} + class TorrentContentTreeView : public QTreeView { Q_OBJECT @@ -39,6 +44,8 @@ public: explicit TorrentContentTreeView(QWidget *parent = nullptr); void keyPressEvent(QKeyEvent *event) override; + void renameSelectedFile(BitTorrent::TorrentHandle *torrent); + private: QModelIndex currentNameCell(); }; From 9c747d3c6dc1ac65cab39aceb5865305419473d2 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Tue, 4 Jun 2019 15:23:27 +0800 Subject: [PATCH 2/4] Move renameSelectedFile(BitTorrent::TorrentInfo &) --- src/gui/addnewtorrentdialog.cpp | 109 ++--------------------------- src/gui/addnewtorrentdialog.h | 1 - src/gui/torrentcontenttreeview.cpp | 105 +++++++++++++++++++++++++++ src/gui/torrentcontenttreeview.h | 2 + 4 files changed, 112 insertions(+), 105 deletions(-) diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 3c53eabe4..cb077db9d 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -151,8 +151,10 @@ 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, &AddNewTorrentDialog::renameSelectedFile); - connect(m_ui->contentTreeView, &QAbstractItemView::doubleClicked, this, &AddNewTorrentDialog::renameSelectedFile); + 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); }); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); } @@ -434,107 +436,6 @@ void AddNewTorrentDialog::setSavePath(const QString &newPath) onSavePathChanged(newPath); } -void AddNewTorrentDialog::renameSelectedFile() -{ - const QModelIndexList selectedIndexes = m_ui->contentTreeView->selectionModel()->selectedRows(0); - if (selectedIndexes.size() != 1) return; - - const QModelIndex modelIndex = selectedIndexes.first(); - if (!modelIndex.isValid()) return; - - // Ask for new name - bool ok = false; - const bool isFile = (m_contentModel->itemType(modelIndex) == TorrentContentModelItem::FileType); - QString newName = AutoExpandableDialog::getText(this, tr("Renaming"), tr("New name:"), QLineEdit::Normal - , modelIndex.data().toString(), &ok, isFile).trimmed(); - if (!ok) return; - - if (newName.isEmpty() || !Utils::Fs::isValidFileSystemName(newName)) { - RaisedMessageBox::warning(this, tr("Rename error"), - tr("The name is empty or contains forbidden characters, please choose a different one."), - QMessageBox::Ok); - return; - } - - if (isFile) { - const int fileIndex = m_contentModel->getFileIndex(modelIndex); - - if (newName.endsWith(QB_EXT)) - newName.chop(QB_EXT.size()); - const QString oldFileName = m_torrentInfo.fileName(fileIndex); - const QString oldFilePath = m_torrentInfo.filePath(fileIndex); - const QString newFilePath = oldFilePath.leftRef(oldFilePath.size() - oldFileName.size()) + newName; - - if (oldFileName == newName) { - qDebug("Name did not change: %s", qUtf8Printable(oldFileName)); - return; - } - - // check if that name is already used - for (int i = 0; i < m_torrentInfo.filesCount(); ++i) { - if (i == fileIndex) continue; - if (Utils::Fs::sameFileNames(m_torrentInfo.filePath(i), newFilePath)) { - RaisedMessageBox::warning(this, tr("Rename error"), - tr("This name is already in use in this folder. Please use a different name."), - QMessageBox::Ok); - return; - } - } - - qDebug("Renaming %s to %s", qUtf8Printable(oldFilePath), qUtf8Printable(newFilePath)); - m_torrentInfo.renameFile(fileIndex, newFilePath); - - m_contentModel->setData(modelIndex, newName); - } - else { - // renaming a folder - QStringList pathItems; - pathItems << modelIndex.data().toString(); - QModelIndex parent = m_contentModel->parent(modelIndex); - while (parent.isValid()) { - pathItems.prepend(parent.data().toString()); - parent = m_contentModel->parent(parent); - } - const QString oldPath = pathItems.join('/'); - pathItems.removeLast(); - pathItems << newName; - QString newPath = pathItems.join('/'); - if (Utils::Fs::sameFileNames(oldPath, newPath)) { - qDebug("Name did not change"); - return; - } - if (!newPath.endsWith('/')) newPath += '/'; - // Check for overwriting - for (int i = 0; i < m_torrentInfo.filesCount(); ++i) { - const QString currentName = m_torrentInfo.filePath(i); -#if defined(Q_OS_UNIX) || defined(Q_WS_QWS) - if (currentName.startsWith(newPath, Qt::CaseSensitive)) { -#else - if (currentName.startsWith(newPath, Qt::CaseInsensitive)) { -#endif - RaisedMessageBox::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 (int i = 0; i < m_torrentInfo.filesCount(); ++i) { - const QString currentName = m_torrentInfo.filePath(i); - if (currentName.startsWith(oldPath)) { - QString newName = currentName; - newName.replace(0, oldPath.length(), newPath); - newName = Utils::Fs::expandPath(newName); - qDebug("Rename %s to %s", qUtf8Printable(currentName), qUtf8Printable(newName)); - m_torrentInfo.renameFile(i, newName); - } - } - - // Rename folder in torrent files model too - m_contentModel->setData(modelIndex, newName); - } -} - void AddNewTorrentDialog::populateSavePathComboBox() { m_ui->savePath->clear(); @@ -574,7 +475,7 @@ void AddNewTorrentDialog::displayContentTreeMenu(const QPoint &) QAction *act = myFilesLlistMenu.exec(QCursor::pos()); if (act) { if (act == actRename) { - renameSelectedFile(); + m_ui->contentTreeView->renameSelectedFile(m_torrentInfo); } else { BitTorrent::DownloadPriority prio = BitTorrent::DownloadPriority::Normal; diff --git a/src/gui/addnewtorrentdialog.h b/src/gui/addnewtorrentdialog.h index eb8f9d598..00ddb9a9d 100644 --- a/src/gui/addnewtorrentdialog.h +++ b/src/gui/addnewtorrentdialog.h @@ -82,7 +82,6 @@ private slots: void displayContentTreeMenu(const QPoint &); void updateDiskSpaceLabel(); void onSavePathChanged(const QString &newPath); - void renameSelectedFile(); void updateMetadata(const BitTorrent::TorrentInfo &info); void handleDownloadFinished(const Net::DownloadResult &result); void TMMChanged(int index); diff --git a/src/gui/torrentcontenttreeview.cpp b/src/gui/torrentcontenttreeview.cpp index 48a7c7a8e..21bdbe5a0 100644 --- a/src/gui/torrentcontenttreeview.cpp +++ b/src/gui/torrentcontenttreeview.cpp @@ -39,6 +39,7 @@ #include "base/bittorrent/session.h" #include "base/bittorrent/torrenthandle.h" +#include "base/bittorrent/torrentinfo.h" #include "base/global.h" #include "base/utils/fs.h" #include "autoexpandabledialog.h" @@ -208,6 +209,110 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentHandle *torre } } +void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentInfo &torrent) +{ + const QModelIndexList selectedIndexes = selectionModel()->selectedRows(0); + if (selectedIndexes.size() != 1) return; + + const QModelIndex modelIndex = selectedIndexes.first(); + if (!modelIndex.isValid()) return; + + auto model = dynamic_cast(TorrentContentTreeView::model()); + if (!model) return; + + // Ask for new name + bool ok = false; + const bool isFile = (model->itemType(modelIndex) == TorrentContentModelItem::FileType); + QString newName = AutoExpandableDialog::getText(this, tr("Renaming"), tr("New name:"), QLineEdit::Normal + , modelIndex.data().toString(), &ok, isFile).trimmed(); + if (!ok) return; + + if (newName.isEmpty() || !Utils::Fs::isValidFileSystemName(newName)) { + RaisedMessageBox::warning(this, tr("Rename error"), + tr("The name is empty or contains forbidden characters, please choose a different one."), + QMessageBox::Ok); + return; + } + + if (isFile) { + const int fileIndex = model->getFileIndex(modelIndex); + + if (newName.endsWith(QB_EXT)) + newName.chop(QB_EXT.size()); + const QString oldFileName = torrent.fileName(fileIndex); + const QString oldFilePath = torrent.filePath(fileIndex); + const QString newFilePath = oldFilePath.leftRef(oldFilePath.size() - oldFileName.size()) + newName; + + if (oldFileName == newName) { + qDebug("Name did not change: %s", qUtf8Printable(oldFileName)); + return; + } + + // check if that name is already used + for (int i = 0; i < torrent.filesCount(); ++i) { + if (i == fileIndex) continue; + if (Utils::Fs::sameFileNames(torrent.filePath(i), newFilePath)) { + RaisedMessageBox::warning(this, tr("Rename error"), + tr("This name is already in use in this folder. Please use a different name."), + QMessageBox::Ok); + return; + } + } + + qDebug("Renaming %s to %s", qUtf8Printable(oldFilePath), qUtf8Printable(newFilePath)); + torrent.renameFile(fileIndex, newFilePath); + + model->setData(modelIndex, newName); + } + else { + // renaming a folder + QStringList pathItems; + pathItems << modelIndex.data().toString(); + QModelIndex parent = model->parent(modelIndex); + while (parent.isValid()) { + pathItems.prepend(parent.data().toString()); + parent = model->parent(parent); + } + const QString oldPath = pathItems.join('/'); + pathItems.removeLast(); + pathItems << newName; + QString newPath = pathItems.join('/'); + if (Utils::Fs::sameFileNames(oldPath, newPath)) { + qDebug("Name did not change"); + return; + } + if (!newPath.endsWith('/')) newPath += '/'; + // Check for overwriting + for (int i = 0; i < torrent.filesCount(); ++i) { + const QString currentName = torrent.filePath(i); +#if defined(Q_OS_UNIX) || defined(Q_WS_QWS) + if (currentName.startsWith(newPath, Qt::CaseSensitive)) { +#else + if (currentName.startsWith(newPath, Qt::CaseInsensitive)) { +#endif + RaisedMessageBox::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 (int i = 0; i < torrent.filesCount(); ++i) { + const QString currentName = torrent.filePath(i); + if (currentName.startsWith(oldPath)) { + QString newName = currentName; + newName.replace(0, oldPath.length(), newPath); + newName = Utils::Fs::expandPath(newName); + qDebug("Rename %s to %s", qUtf8Printable(currentName), qUtf8Printable(newName)); + torrent.renameFile(i, newName); + } + } + + // Rename folder in torrent files model too + model->setData(modelIndex, newName); + } +} + QModelIndex TorrentContentTreeView::currentNameCell() { QModelIndex current = currentIndex(); diff --git a/src/gui/torrentcontenttreeview.h b/src/gui/torrentcontenttreeview.h index d2d75e25a..b44c395af 100644 --- a/src/gui/torrentcontenttreeview.h +++ b/src/gui/torrentcontenttreeview.h @@ -34,6 +34,7 @@ namespace BitTorrent { class TorrentHandle; + class TorrentInfo; } class TorrentContentTreeView : public QTreeView @@ -45,6 +46,7 @@ public: void keyPressEvent(QKeyEvent *event) override; void renameSelectedFile(BitTorrent::TorrentHandle *torrent); + void renameSelectedFile(BitTorrent::TorrentInfo &torrent); private: QModelIndex currentNameCell(); From eabcae10186176e91c2f065c9e4ab7f2678b5cf4 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Tue, 4 Jun 2019 15:32:12 +0800 Subject: [PATCH 3/4] Fix unable to rename folder on Windows The bug occurs when the new path and old path only differ by letter case. --- src/gui/torrentcontenttreeview.cpp | 151 +++++++++++++++-------------- 1 file changed, 80 insertions(+), 71 deletions(-) diff --git a/src/gui/torrentcontenttreeview.cpp b/src/gui/torrentcontenttreeview.cpp index 21bdbe5a0..1a0761a23 100644 --- a/src/gui/torrentcontenttreeview.cpp +++ b/src/gui/torrentcontenttreeview.cpp @@ -100,9 +100,10 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentHandle *torre auto model = dynamic_cast(TorrentContentTreeView::model()); if (!model) return; + const bool isFile = (model->itemType(modelIndex) == TorrentContentModelItem::FileType); + // Ask for new name bool ok = false; - const bool isFile = (model->itemType(modelIndex) == TorrentContentModelItem::FileType); QString newName = AutoExpandableDialog::getText(this, tr("Renaming"), tr("New name:"), QLineEdit::Normal , modelIndex.data().toString(), &ok, isFile).trimmed(); if (!ok) return; @@ -150,62 +151,69 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentHandle *torre } else { // renaming a folder - QStringList pathItems; - pathItems << modelIndex.data().toString(); - QModelIndex parent = model->parent(modelIndex); - while (parent.isValid()) { - pathItems.prepend(parent.data().toString()); - parent = model->parent(parent); - } - const QString oldPath = pathItems.join('/'); - pathItems.removeLast(); - pathItems << newName; - QString newPath = pathItems.join('/'); - if (Utils::Fs::sameFileNames(oldPath, newPath)) { - qDebug("Name did not change"); - return; - } - if (!newPath.endsWith('/')) newPath += '/'; + + const QString oldName = modelIndex.data().toString(); + if (newName == oldName) + return; // Name did not change + + QString parentPath; + for (QModelIndex idx = model->parent(modelIndex); idx.isValid(); idx = model->parent(idx)) + parentPath.prepend(idx.data().toString() + '/'); + + const QString oldPath {parentPath + oldName + '/'}; + const QString newPath {parentPath + newName + '/'}; + // Check for overwriting - for (int i = 0; i < torrent->filesCount(); ++i) { - const QString currentName = torrent->filePath(i); -#if defined(Q_OS_UNIX) || defined(Q_WS_QWS) - if (currentName.startsWith(newPath, Qt::CaseSensitive)) { +#if defined(Q_OS_WIN) + const Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; #else - if (currentName.startsWith(newPath, Qt::CaseInsensitive)) { + const Qt::CaseSensitivity caseSensitivity = 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); + + for (int i = 0; i < torrent->filesCount(); ++i) { + const QString currentPath = torrent->filePath(i); + + if (currentPath.startsWith(oldPath)) + continue; + + if (currentPath.startsWith(newPath, caseSensitivity)) { + RaisedMessageBox::warning(this, tr("The folder could not be renamed"), + tr("This name is already in use. Please use a different name."), + QMessageBox::Ok); return; } } - bool forceRecheck = false; + // Replace path in all files + bool needForceRecheck = false; + for (int i = 0; i < torrent->filesCount(); ++i) { - const QString currentName = torrent->filePath(i); - if (currentName.startsWith(oldPath)) { - QString newName = currentName; - newName.replace(0, oldPath.length(), newPath); - if (!forceRecheck && QDir(torrent->savePath(true)).exists(newName)) - forceRecheck = true; - newName = Utils::Fs::expandPath(newName); - qDebug("Rename %s to %s", qUtf8Printable(currentName), qUtf8Printable(newName)); - torrent->renameFile(i, newName); + const QString currentPath = torrent->filePath(i); + + if (currentPath.startsWith(oldPath)) { + const QString path {newPath + currentPath.mid(oldPath.length())}; + + if (!needForceRecheck && QFile::exists(path)) + needForceRecheck = true; + + torrent->renameFile(i, path); } } + // Force recheck - if (forceRecheck) torrent->forceRecheck(); - // Rename folder in torrent files model too - model->setData(modelIndex, newName); + if (needForceRecheck) + torrent->forceRecheck(); + // Remove old folder - const QDir oldFolder(torrent->savePath(true) + '/' + oldPath); + const QString oldFullPath = torrent->savePath(true) + oldPath; int timeout = 10; - while (!QDir().rmpath(oldFolder.absolutePath()) && (timeout > 0)) { + while (!QDir().rmpath(oldFullPath) && (timeout > 0)) { // FIXME: We should not sleep here (freezes the UI for 1 second) QThread::msleep(100); --timeout; } + + model->setData(modelIndex, newName); } } @@ -220,9 +228,10 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentInfo &torrent auto model = dynamic_cast(TorrentContentTreeView::model()); if (!model) return; + const bool isFile = (model->itemType(modelIndex) == TorrentContentModelItem::FileType); + // Ask for new name bool ok = false; - const bool isFile = (model->itemType(modelIndex) == TorrentContentModelItem::FileType); QString newName = AutoExpandableDialog::getText(this, tr("Renaming"), tr("New name:"), QLineEdit::Normal , modelIndex.data().toString(), &ok, isFile).trimmed(); if (!ok) return; @@ -266,49 +275,49 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentInfo &torrent } else { // renaming a folder - QStringList pathItems; - pathItems << modelIndex.data().toString(); - QModelIndex parent = model->parent(modelIndex); - while (parent.isValid()) { - pathItems.prepend(parent.data().toString()); - parent = model->parent(parent); - } - const QString oldPath = pathItems.join('/'); - pathItems.removeLast(); - pathItems << newName; - QString newPath = pathItems.join('/'); - if (Utils::Fs::sameFileNames(oldPath, newPath)) { - qDebug("Name did not change"); - return; - } - if (!newPath.endsWith('/')) newPath += '/'; + + const QString oldName = modelIndex.data().toString(); + if (newName == oldName) + return; // Name did not change + + QString parentPath; + for (QModelIndex idx = model->parent(modelIndex); idx.isValid(); idx = model->parent(idx)) + parentPath.prepend(idx.data().toString() + '/'); + + const QString oldPath {parentPath + oldName + '/'}; + const QString newPath {parentPath + newName + '/'}; + // Check for overwriting - for (int i = 0; i < torrent.filesCount(); ++i) { - const QString currentName = torrent.filePath(i); -#if defined(Q_OS_UNIX) || defined(Q_WS_QWS) - if (currentName.startsWith(newPath, Qt::CaseSensitive)) { +#if defined(Q_OS_WIN) + const Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; #else - if (currentName.startsWith(newPath, Qt::CaseInsensitive)) { + const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; #endif + + for (int i = 0; i < torrent.filesCount(); ++i) { + const QString currentPath = torrent.filePath(i); + + if (currentPath.startsWith(oldPath)) + continue; + + if (currentPath.startsWith(newPath, caseSensitivity)) { RaisedMessageBox::warning(this, tr("The folder could not be renamed"), - tr("This name is already in use in this folder. Please use a different name."), + tr("This name is already in use. Please use a different name."), QMessageBox::Ok); return; } } + // Replace path in all files for (int i = 0; i < torrent.filesCount(); ++i) { - const QString currentName = torrent.filePath(i); - if (currentName.startsWith(oldPath)) { - QString newName = currentName; - newName.replace(0, oldPath.length(), newPath); - newName = Utils::Fs::expandPath(newName); - qDebug("Rename %s to %s", qUtf8Printable(currentName), qUtf8Printable(newName)); - torrent.renameFile(i, newName); + const QString currentPath = torrent.filePath(i); + + if (currentPath.startsWith(oldPath)) { + const QString path {newPath + currentPath.mid(oldPath.length())}; + torrent.renameFile(i, path); } } - // Rename folder in torrent files model too model->setData(modelIndex, newName); } } From 8191f1498a56e2da92eb2055c487cfeed65a29dc Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Tue, 4 Jun 2019 18:49:51 +0800 Subject: [PATCH 4/4] Log file rename failed errors --- src/base/bittorrent/torrenthandle.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/base/bittorrent/torrenthandle.cpp b/src/base/bittorrent/torrenthandle.cpp index d807212ea..41a1a0a05 100644 --- a/src/base/bittorrent/torrenthandle.cpp +++ b/src/base/bittorrent/torrenthandle.cpp @@ -1479,10 +1479,9 @@ void TorrentHandle::moveStorage(const QString &newPath, bool overwrite) } } -void TorrentHandle::renameFile(int index, const QString &name) +void TorrentHandle::renameFile(const int index, const QString &name) { ++m_renameCount; - qDebug() << Q_FUNC_INFO << index << name; m_nativeHandle.rename_file(index, Utils::Fs::toNativePath(name).toStdString()); } @@ -1777,6 +1776,10 @@ void TorrentHandle::handleFileRenameFailedAlert(const lt::file_rename_failed_ale { Q_UNUSED(p); + LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"") + .arg(name(), filePath(p->index) + , QString::fromStdString(p->error.message())), Log::WARNING); + --m_renameCount; while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty()) m_moveFinishedTriggers.takeFirst()();