Implement class for handling filesystem paths

PR #15915.
This commit is contained in:
Vladimir Golovnev
2022-02-08 06:03:48 +03:00
committed by GitHub
parent facfa26eed
commit dd1bd8ad10
131 changed files with 2252 additions and 1868 deletions

View File

@@ -30,6 +30,7 @@
#include <QFile>
#include "base/path.h"
#include "base/unicodestrings.h"
#include "base/utils/misc.h"
#include "base/version.h"
@@ -70,7 +71,7 @@ AboutDialog::AboutDialog(QWidget *parent)
, tr("Bug Tracker:"));
m_ui->labelAbout->setText(aboutText);
m_ui->labelMascot->setPixmap(Utils::Gui::scaledPixmap(":/icons/mascot.png", this));
m_ui->labelMascot->setPixmap(Utils::Gui::scaledPixmap(Path(":/icons/mascot.png"), this));
// Thanks
QFile thanksfile(":/thanks.html");

View File

@@ -81,7 +81,7 @@ namespace
class FileStorageAdaptor final : public BitTorrent::AbstractFileStorage
{
public:
FileStorageAdaptor(const BitTorrent::TorrentInfo &torrentInfo, QStringList &filePaths)
FileStorageAdaptor(const BitTorrent::TorrentInfo &torrentInfo, PathList &filePaths)
: m_torrentInfo {torrentInfo}
, m_filePaths {filePaths}
{
@@ -99,16 +99,16 @@ namespace
return m_torrentInfo.fileSize(index);
}
QString filePath(const int index) const override
Path filePath(const int index) const override
{
Q_ASSERT((index >= 0) && (index < filesCount()));
return (m_filePaths.isEmpty() ? m_torrentInfo.filePath(index) : m_filePaths.at(index));
}
void renameFile(const int index, const QString &newFilePath) override
void renameFile(const int index, const Path &newFilePath) override
{
Q_ASSERT((index >= 0) && (index < filesCount()));
const QString currentFilePath = filePath(index);
const Path currentFilePath = filePath(index);
if (currentFilePath == newFilePath)
return;
@@ -120,22 +120,21 @@ namespace
private:
const BitTorrent::TorrentInfo &m_torrentInfo;
QStringList &m_filePaths;
PathList &m_filePaths;
};
// savePath is a folder, not an absolute file path
int indexOfPath(const FileSystemPathComboEdit *fsPathEdit, const QString &savePath)
int indexOfPath(const FileSystemPathComboEdit *fsPathEdit, const Path &savePath)
{
const QDir saveDir {savePath};
for (int i = 0; i < fsPathEdit->count(); ++i)
{
if (QDir(fsPathEdit->item(i)) == saveDir)
if (fsPathEdit->item(i) == savePath)
return i;
}
return -1;
}
void setPath(FileSystemPathComboEdit *fsPathEdit, const QString &newPath)
void setPath(FileSystemPathComboEdit *fsPathEdit, const Path &newPath)
{
int existingIndex = indexOfPath(fsPathEdit, newPath);
if (existingIndex < 0)
@@ -148,16 +147,18 @@ namespace
fsPathEdit->setCurrentIndex(existingIndex);
}
void updatePathHistory(const QString &settingsKey, const QString &path, const int maxLength)
void updatePathHistory(const QString &settingsKey, const Path &path, const int maxLength)
{
// Add last used save path to the front of history
auto pathList = settings()->loadValue<QStringList>(settingsKey);
const int selectedSavePathIndex = pathList.indexOf(path);
const int selectedSavePathIndex = pathList.indexOf(path.toString());
if (selectedSavePathIndex > -1)
pathList.move(selectedSavePathIndex, 0);
else
pathList.prepend(path);
pathList.prepend(path.toString());
settings()->storeValue(settingsKey, QStringList(pathList.mid(0, maxLength)));
}
}
@@ -325,7 +326,7 @@ void AddNewTorrentDialog::show(const QString &source, const BitTorrent::AddTorre
return;
}
const BitTorrent::MagnetUri magnetUri(source);
const BitTorrent::MagnetUri magnetUri {source};
const bool isLoaded = magnetUri.isValid()
? dlg->loadMagnet(magnetUri)
: dlg->loadTorrentFile(source);
@@ -341,18 +342,18 @@ void AddNewTorrentDialog::show(const QString &source, QWidget *parent)
show(source, BitTorrent::AddTorrentParams(), parent);
}
bool AddNewTorrentDialog::loadTorrentFile(const QString &torrentPath)
bool AddNewTorrentDialog::loadTorrentFile(const QString &source)
{
const QString decodedPath = torrentPath.startsWith("file://", Qt::CaseInsensitive)
? QUrl::fromEncoded(torrentPath.toLocal8Bit()).toLocalFile()
: torrentPath;
const Path decodedPath {source.startsWith("file://", Qt::CaseInsensitive)
? QUrl::fromEncoded(source.toLocal8Bit()).toLocalFile()
: source};
const nonstd::expected<BitTorrent::TorrentInfo, QString> result = BitTorrent::TorrentInfo::loadFromFile(decodedPath);
if (!result)
{
RaisedMessageBox::critical(this, tr("Invalid torrent")
, tr("Failed to load the torrent: %1.\nError: %2", "Don't remove the '\n' characters. They insert a newline.")
.arg(Utils::Fs::toNativePath(decodedPath), result.error()));
.arg(decodedPath.toString(), result.error()));
return false;
}
@@ -489,7 +490,7 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
m_ui->labelSizeData->setText(sizeString);
}
void AddNewTorrentDialog::onSavePathChanged(const QString &newPath)
void AddNewTorrentDialog::onSavePathChanged(const Path &newPath)
{
Q_UNUSED(newPath);
// Remember index
@@ -497,7 +498,7 @@ void AddNewTorrentDialog::onSavePathChanged(const QString &newPath)
updateDiskSpaceLabel();
}
void AddNewTorrentDialog::onDownloadPathChanged(const QString &newPath)
void AddNewTorrentDialog::onDownloadPathChanged(const Path &newPath)
{
Q_UNUSED(newPath);
// Remember index
@@ -521,11 +522,11 @@ void AddNewTorrentDialog::categoryChanged(int index)
const auto *btSession = BitTorrent::Session::instance();
const QString categoryName = m_ui->categoryComboBox->currentText();
const QString savePath = btSession->categorySavePath(categoryName);
m_ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath));
const Path savePath = btSession->categorySavePath(categoryName);
m_ui->savePath->setSelectedPath(savePath);
const QString downloadPath = btSession->categoryDownloadPath(categoryName);
m_ui->downloadPath->setSelectedPath(Utils::Fs::toNativePath(downloadPath));
const Path downloadPath = btSession->categoryDownloadPath(categoryName);
m_ui->downloadPath->setSelectedPath(downloadPath);
m_ui->groupBoxDownloadPath->setChecked(!m_ui->downloadPath->selectedPath().isEmpty());
@@ -545,7 +546,7 @@ void AddNewTorrentDialog::contentLayoutChanged(const int index)
const auto contentLayout = ((index == 0)
? BitTorrent::detectContentLayout(m_torrentInfo.filePaths())
: static_cast<BitTorrent::TorrentContentLayout>(index));
BitTorrent::applyContentLayout(m_torrentParams.filePaths, contentLayout, Utils::Fs::findRootFolder(m_torrentInfo.filePaths()));
BitTorrent::applyContentLayout(m_torrentParams.filePaths, contentLayout, Path::findRootFolder(m_torrentInfo.filePaths()));
m_contentModel->model()->setupModelData(FileStorageAdaptor(m_torrentInfo, m_torrentParams.filePaths));
m_contentModel->model()->updateFilesPriorities(filePriorities);
@@ -574,7 +575,7 @@ void AddNewTorrentDialog::saveTorrentFile()
if (!path.endsWith(torrentFileExtension, Qt::CaseInsensitive))
path += torrentFileExtension;
const nonstd::expected<void, QString> result = m_torrentInfo.saveToFile(path);
const nonstd::expected<void, QString> result = m_torrentInfo.saveToFile(Path(path));
if (!result)
{
QMessageBox::critical(this, tr("I/O Error")
@@ -597,7 +598,7 @@ void AddNewTorrentDialog::populateSavePaths()
if (savePathHistory.size() > 0)
{
for (const QString &path : savePathHistory)
m_ui->savePath->addItem(path);
m_ui->savePath->addItem(Path(path));
}
else
{
@@ -628,7 +629,7 @@ void AddNewTorrentDialog::populateSavePaths()
if (downloadPathHistory.size() > 0)
{
for (const QString &path : downloadPathHistory)
m_ui->downloadPath->addItem(path);
m_ui->downloadPath->addItem(Path(path));
}
else
{
@@ -806,14 +807,14 @@ void AddNewTorrentDialog::accept()
m_torrentParams.useAutoTMM = useAutoTMM;
if (!useAutoTMM)
{
const QString savePath = m_ui->savePath->selectedPath();
const Path savePath = m_ui->savePath->selectedPath();
m_torrentParams.savePath = savePath;
updatePathHistory(KEY_SAVEPATHHISTORY, savePath, savePathHistoryLength());
m_torrentParams.useDownloadPath = m_ui->groupBoxDownloadPath->isChecked();
if (m_torrentParams.useDownloadPath)
{
const QString downloadPath = m_ui->downloadPath->selectedPath();
const Path downloadPath = m_ui->downloadPath->selectedPath();
m_torrentParams.downloadPath = downloadPath;
updatePathHistory(KEY_DOWNLOADPATHHISTORY, downloadPath, savePathHistoryLength());
}
@@ -907,7 +908,7 @@ void AddNewTorrentDialog::setupTreeview()
: static_cast<BitTorrent::TorrentContentLayout>(m_ui->contentLayoutComboBox->currentIndex()));
if (m_torrentParams.filePaths.isEmpty())
m_torrentParams.filePaths = m_torrentInfo.filePaths();
BitTorrent::applyContentLayout(m_torrentParams.filePaths, contentLayout, Utils::Fs::findRootFolder(m_torrentInfo.filePaths()));
BitTorrent::applyContentLayout(m_torrentParams.filePaths, contentLayout, Path::findRootFolder(m_torrentInfo.filePaths()));
// List files in torrent
m_contentModel->model()->setupModelData(FileStorageAdaptor(m_torrentInfo, m_torrentParams.filePaths));
if (const QByteArray state = m_storeTreeHeaderState; !state.isEmpty())
@@ -981,12 +982,12 @@ void AddNewTorrentDialog::TMMChanged(int index)
m_ui->savePath->blockSignals(true);
m_ui->savePath->clear();
const QString savePath = session->categorySavePath(m_ui->categoryComboBox->currentText());
const Path savePath = session->categorySavePath(m_ui->categoryComboBox->currentText());
m_ui->savePath->addItem(savePath);
m_ui->downloadPath->blockSignals(true);
m_ui->downloadPath->clear();
const QString downloadPath = session->categoryDownloadPath(m_ui->categoryComboBox->currentText());
const Path downloadPath = session->categoryDownloadPath(m_ui->categoryComboBox->currentText());
m_ui->downloadPath->addItem(downloadPath);
m_ui->groupBoxDownloadPath->blockSignals(true);

View File

@@ -81,8 +81,8 @@ private slots:
void displayContentTreeMenu();
void displayColumnHeaderMenu();
void updateDiskSpaceLabel();
void onSavePathChanged(const QString &newPath);
void onDownloadPathChanged(const QString &newPath);
void onSavePathChanged(const Path &newPath);
void onDownloadPathChanged(const Path &newPath);
void onUseDownloadPathChanged(bool checked);
void updateMetadata(const BitTorrent::TorrentInfo &metadata);
void handleDownloadFinished(const Net::DownloadResult &downloadResult);
@@ -97,7 +97,7 @@ private slots:
private:
explicit AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inParams, QWidget *parent);
bool loadTorrentFile(const QString &torrentPath);
bool loadTorrentFile(const QString &source);
bool loadTorrentImpl();
bool loadMagnet(const BitTorrent::MagnetUri &magnetUri);
void populateSavePaths();

View File

@@ -28,7 +28,7 @@
#include "autoexpandabledialog.h"
#include "base/utils/fs.h"
#include "base/path.h"
#include "ui_autoexpandabledialog.h"
#include "utils.h"
@@ -58,9 +58,9 @@ QString AutoExpandableDialog::getText(QWidget *parent, const QString &title, con
d.m_ui->textEdit->selectAll();
if (excludeExtension)
{
const QString extension = Utils::Fs::fileExtension(text);
const QString extension = Path(text).extension();
if (!extension.isEmpty())
d.m_ui->textEdit->setSelection(0, (text.length() - extension.length() - 1));
d.m_ui->textEdit->setSelection(0, (text.length() - extension.length()));
}
bool res = d.exec();

View File

@@ -82,7 +82,7 @@ class FileSystemPathEdit::FileSystemPathEditPrivate
QToolButton *m_browseBtn;
QString m_fileNameFilter;
Mode m_mode;
QString m_lastSignaledPath;
Path m_lastSignaledPath;
QString m_dialogCaption;
Private::FileSystemPathValidator *m_validator;
};
@@ -112,31 +112,32 @@ void FileSystemPathEdit::FileSystemPathEditPrivate::browseActionTriggered()
{
Q_Q(FileSystemPathEdit);
const QFileInfo fileInfo {q->selectedPath()};
const QString directory = (m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave)
? fileInfo.absoluteFilePath()
: fileInfo.absolutePath();
QString filter = q->fileNameFilter();
const Path currentDirectory = (m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave)
? q->selectedPath()
: q->selectedPath().parentPath();
const Path initialDirectory = currentDirectory.isAbsolute() ? currentDirectory : (Utils::Fs::homePath() / currentDirectory);
QString selectedPath;
QString filter = q->fileNameFilter();
QString newPath;
switch (m_mode)
{
case FileSystemPathEdit::Mode::FileOpen:
selectedPath = QFileDialog::getOpenFileName(q, dialogCaptionOrDefault(), directory, filter);
newPath = QFileDialog::getOpenFileName(q, dialogCaptionOrDefault(), initialDirectory.data(), filter);
break;
case FileSystemPathEdit::Mode::FileSave:
selectedPath = QFileDialog::getSaveFileName(q, dialogCaptionOrDefault(), directory, filter, &filter);
newPath = QFileDialog::getSaveFileName(q, dialogCaptionOrDefault(), initialDirectory.data(), filter, &filter);
break;
case FileSystemPathEdit::Mode::DirectoryOpen:
case FileSystemPathEdit::Mode::DirectorySave:
selectedPath = QFileDialog::getExistingDirectory(q, dialogCaptionOrDefault(),
directory, QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly);
newPath = QFileDialog::getExistingDirectory(q, dialogCaptionOrDefault(),
initialDirectory.data(), QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly);
break;
default:
throw std::logic_error("Unknown FileSystemPathEdit mode");
}
if (!selectedPath.isEmpty())
q->setEditWidgetText(Utils::Fs::toNativePath(selectedPath));
if (!newPath.isEmpty())
q->setSelectedPath(Path(newPath));
}
QString FileSystemPathEdit::FileSystemPathEditPrivate::dialogCaptionOrDefault() const
@@ -202,16 +203,18 @@ FileSystemPathEdit::~FileSystemPathEdit()
delete d_ptr;
}
QString FileSystemPathEdit::selectedPath() const
Path FileSystemPathEdit::selectedPath() const
{
return Utils::Fs::toUniformPath(editWidgetText());
return Path(editWidgetText());
}
void FileSystemPathEdit::setSelectedPath(const QString &val)
void FileSystemPathEdit::setSelectedPath(const Path &val)
{
Q_D(FileSystemPathEdit);
setEditWidgetText(Utils::Fs::toNativePath(val));
d->m_editor->widget()->setToolTip(val);
const QString nativePath = val.toString();
setEditWidgetText(nativePath);
d->m_editor->widget()->setToolTip(nativePath);
}
QString FileSystemPathEdit::fileNameFilter() const
@@ -251,13 +254,13 @@ void FileSystemPathEdit::setFileNameFilter(const QString &val)
#endif
}
QString FileSystemPathEdit::placeholder() const
Path FileSystemPathEdit::placeholder() const
{
Q_D(const FileSystemPathEdit);
return d->m_editor->placeholder();
}
void FileSystemPathEdit::setPlaceholder(const QString &val)
void FileSystemPathEdit::setPlaceholder(const Path &val)
{
Q_D(FileSystemPathEdit);
d->m_editor->setPlaceholder(val);
@@ -278,7 +281,8 @@ void FileSystemPathEdit::setBriefBrowseButtonCaption(bool brief)
void FileSystemPathEdit::onPathEdited()
{
Q_D(FileSystemPathEdit);
QString newPath = selectedPath();
const Path newPath = selectedPath();
if (newPath != d->m_lastSignaledPath)
{
emit selectedPathChanged(newPath);
@@ -360,19 +364,19 @@ int FileSystemPathComboEdit::count() const
return editWidget<WidgetType>()->count();
}
QString FileSystemPathComboEdit::item(int index) const
Path FileSystemPathComboEdit::item(int index) const
{
return Utils::Fs::toUniformPath(editWidget<WidgetType>()->itemText(index));
return Path(editWidget<WidgetType>()->itemText(index));
}
void FileSystemPathComboEdit::addItem(const QString &text)
void FileSystemPathComboEdit::addItem(const Path &path)
{
editWidget<WidgetType>()->addItem(Utils::Fs::toNativePath(text));
editWidget<WidgetType>()->addItem(path.toString());
}
void FileSystemPathComboEdit::insertItem(int index, const QString &text)
void FileSystemPathComboEdit::insertItem(int index, const Path &path)
{
editWidget<WidgetType>()->insertItem(index, Utils::Fs::toNativePath(text));
editWidget<WidgetType>()->insertItem(index, path.toString());
}
int FileSystemPathComboEdit::currentIndex() const

View File

@@ -30,6 +30,8 @@
#include <QWidget>
#include "base/path.h"
namespace Private
{
class FileComboEdit;
@@ -45,7 +47,7 @@ class FileSystemPathEdit : public QWidget
{
Q_OBJECT
Q_PROPERTY(Mode mode READ mode WRITE setMode)
Q_PROPERTY(QString selectedPath READ selectedPath WRITE setSelectedPath NOTIFY selectedPathChanged)
Q_PROPERTY(Path selectedPath READ selectedPath WRITE setSelectedPath NOTIFY selectedPathChanged)
Q_PROPERTY(QString fileNameFilter READ fileNameFilter WRITE setFileNameFilter)
Q_PROPERTY(QString dialogCaption READ dialogCaption WRITE setDialogCaption)
@@ -64,14 +66,14 @@ public:
Mode mode() const;
void setMode(Mode mode);
QString selectedPath() const;
void setSelectedPath(const QString &val);
Path selectedPath() const;
void setSelectedPath(const Path &val);
QString fileNameFilter() const;
void setFileNameFilter(const QString &val);
QString placeholder() const;
void setPlaceholder(const QString &val);
Path placeholder() const;
void setPlaceholder(const Path &val);
/// The browse button caption is "..." if true, and "Browse" otherwise
bool briefBrowseButtonCaption() const;
@@ -83,7 +85,7 @@ public:
virtual void clear() = 0;
signals:
void selectedPathChanged(const QString &path);
void selectedPathChanged(const Path &path);
protected:
explicit FileSystemPathEdit(Private::FileEditorWithCompletion *editor, QWidget *parent);
@@ -136,9 +138,9 @@ public:
void clear() override;
int count() const;
QString item(int index) const;
void addItem(const QString &text);
void insertItem(int index, const QString &text);
Path item(int index) const;
void addItem(const Path &path);
void insertItem(int index, const Path &path);
int currentIndex() const;
void setCurrentIndex(int index);

View File

@@ -37,6 +37,8 @@
#include <QStringList>
#include <QStyle>
#include "base/path.h"
// -------------------- FileSystemPathValidator ----------------------------------------
Private::FileSystemPathValidator::FileSystemPathValidator(QObject *parent)
: QValidator(parent)
@@ -149,7 +151,7 @@ QValidator::State Private::FileSystemPathValidator::validate(const QList<QString
const QStringView componentPath = pathComponents[i];
if (componentPath.isEmpty()) continue;
m_lastTestResult = testPath(pathComponents[i], isFinalPath);
m_lastTestResult = testPath(Path(pathComponents[i].toString()), isFinalPath);
if (m_lastTestResult != TestResult::OK)
{
m_lastTestedPath = componentPath.toString();
@@ -161,9 +163,9 @@ QValidator::State Private::FileSystemPathValidator::validate(const QList<QString
}
Private::FileSystemPathValidator::TestResult
Private::FileSystemPathValidator::testPath(const QStringView path, bool pathIsComplete) const
Private::FileSystemPathValidator::testPath(const Path &path, bool pathIsComplete) const
{
QFileInfo fi(path.toString());
QFileInfo fi {path.data()};
if (m_existingOnly && !fi.exists())
return TestResult::DoesNotExist;
@@ -240,14 +242,14 @@ void Private::FileLineEdit::setValidator(QValidator *validator)
QLineEdit::setValidator(validator);
}
QString Private::FileLineEdit::placeholder() const
Path Private::FileLineEdit::placeholder() const
{
return placeholderText();
return Path(placeholderText());
}
void Private::FileLineEdit::setPlaceholder(const QString &val)
void Private::FileLineEdit::setPlaceholder(const Path &val)
{
setPlaceholderText(val);
setPlaceholderText(val.toString());
}
QWidget *Private::FileLineEdit::widget()
@@ -356,14 +358,14 @@ void Private::FileComboEdit::setValidator(QValidator *validator)
lineEdit()->setValidator(validator);
}
QString Private::FileComboEdit::placeholder() const
Path Private::FileComboEdit::placeholder() const
{
return lineEdit()->placeholderText();
return Path(lineEdit()->placeholderText());
}
void Private::FileComboEdit::setPlaceholder(const QString &val)
void Private::FileComboEdit::setPlaceholder(const Path &val)
{
lineEdit()->setPlaceholderText(val);
lineEdit()->setPlaceholderText(val.toString());
}
void Private::FileComboEdit::setFilenameFilters(const QStringList &filters)

View File

@@ -34,6 +34,8 @@
#include <QtContainerFwd>
#include <QValidator>
#include "base/pathfwd.h"
class QAction;
class QCompleter;
class QContextMenuEvent;
@@ -84,7 +86,7 @@ namespace Private
QValidator::State validate(const QList<QStringView> &pathComponents, bool strict,
int firstComponentToTest, int lastComponentToTest) const;
TestResult testPath(QStringView path, bool pathIsComplete) const;
TestResult testPath(const Path &path, bool pathIsComplete) const;
bool m_strictMode;
bool m_existingOnly;
@@ -105,8 +107,8 @@ namespace Private
virtual void setFilenameFilters(const QStringList &filters) = 0;
virtual void setBrowseAction(QAction *action) = 0;
virtual void setValidator(QValidator *validator) = 0;
virtual QString placeholder() const = 0;
virtual void setPlaceholder(const QString &val) = 0;
virtual Path placeholder() const = 0;
virtual void setPlaceholder(const Path &val) = 0;
virtual QWidget *widget() = 0;
};
@@ -123,8 +125,8 @@ namespace Private
void setFilenameFilters(const QStringList &filters) override;
void setBrowseAction(QAction *action) override;
void setValidator(QValidator *validator) override;
QString placeholder() const override;
void setPlaceholder(const QString &val) override;
Path placeholder() const override;
void setPlaceholder(const Path &val) override;
QWidget *widget() override;
protected:
@@ -153,8 +155,8 @@ namespace Private
void setFilenameFilters(const QStringList &filters) override;
void setBrowseAction(QAction *action) override;
void setValidator(QValidator *validator) override;
QString placeholder() const override;
void setPlaceholder(const QString &val) override;
Path placeholder() const override;
void setPlaceholder(const Path &val) override;
QWidget *widget() override;
protected:

View File

@@ -30,7 +30,7 @@
#include <objc/objc.h>
#include <QSet>
#include "base/pathfwd.h"
class QPixmap;
class QSize;
@@ -41,7 +41,7 @@ namespace MacUtils
QPixmap pixmapForExtension(const QString &ext, const QSize &size);
void overrideDockClickHandler(bool (*dockClickHandler)(id, SEL, ...));
void displayNotification(const QString &title, const QString &message);
void openFiles(const QSet<QString> &pathsList);
void openFiles(const PathList &pathList);
QString badgeLabelText();
void setBadgeLabelText(const QString &text);

View File

@@ -32,9 +32,11 @@
#include <objc/message.h>
#include <QPixmap>
#include <QSet>
#include <QSize>
#include <QString>
#include <QVector>
#include "base/path.h"
QImage qt_mac_toQImage(CGImageRef image);
@@ -95,14 +97,14 @@ namespace MacUtils
}
}
void openFiles(const QSet<QString> &pathsList)
void openFiles(const PathList &pathList)
{
@autoreleasepool
{
NSMutableArray *pathURLs = [NSMutableArray arrayWithCapacity:pathsList.size()];
NSMutableArray *pathURLs = [NSMutableArray arrayWithCapacity:pathList.size()];
for (const auto &path : pathsList)
[pathURLs addObject:[NSURL fileURLWithPath:path.toNSString()]];
for (const auto &path : pathList)
[pathURLs addObject:[NSURL fileURLWithPath:path.toString().toNSString()]];
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:pathURLs];
}

View File

@@ -58,6 +58,7 @@
#include "base/bittorrent/sessionstatus.h"
#include "base/global.h"
#include "base/net/downloadmanager.h"
#include "base/path.h"
#include "base/preferences.h"
#include "base/rss/rss_folder.h"
#include "base/rss/rss_session.h"
@@ -1250,10 +1251,10 @@ void MainWindow::closeEvent(QCloseEvent *e)
// Display window to create a torrent
void MainWindow::on_actionCreateTorrent_triggered()
{
createTorrentTriggered();
createTorrentTriggered({});
}
void MainWindow::createTorrentTriggered(const QString &path)
void MainWindow::createTorrentTriggered(const Path &path)
{
if (m_createTorrentDlg)
{
@@ -1261,7 +1262,9 @@ void MainWindow::createTorrentTriggered(const QString &path)
m_createTorrentDlg->activateWindow();
}
else
{
m_createTorrentDlg = new TorrentCreatorDialog(this, path);
}
}
bool MainWindow::event(QEvent *e)
@@ -1367,7 +1370,7 @@ void MainWindow::dropEvent(QDropEvent *event)
// Create torrent
for (const QString &file : asConst(otherFiles))
{
createTorrentTriggered(file);
createTorrentTriggered(Path(file));
// currently only handle the first entry
// this is a stub that can be expanded later to create many torrents at once
@@ -1423,7 +1426,7 @@ void MainWindow::on_actionOpen_triggered()
// Open File Open Dialog
// Note: it is possible to select more than one file
const QStringList pathsList =
QFileDialog::getOpenFileNames(this, tr("Open Torrent Files"), pref->getMainLastDir(),
QFileDialog::getOpenFileNames(this, tr("Open Torrent Files"), pref->getMainLastDir().data(),
tr("Torrent Files") + " (*" + C_TORRENT_FILE_EXTENSION + ')');
if (pathsList.isEmpty())
@@ -1440,9 +1443,9 @@ void MainWindow::on_actionOpen_triggered()
}
// Save last dir to remember it
QString topDir = Utils::Fs::toUniformPath(pathsList.at(0));
topDir = topDir.left(topDir.lastIndexOf('/'));
pref->setMainLastDir(topDir);
const Path topDir {pathsList.at(0)};
const Path parentDir = topDir.parentPath();
pref->setMainLastDir(parentDir.isEmpty() ? topDir : parentDir);
}
void MainWindow::activate()
@@ -2110,9 +2113,9 @@ void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result)
QProcess installer;
qDebug("Launching Python installer in passive mode...");
const QString exePath = result.filePath + QLatin1String(".exe");
QFile::rename(result.filePath, exePath);
installer.start(Utils::Fs::toNativePath(exePath), {"/passive"});
const Path exePath = result.filePath + ".exe";
Utils::Fs::renameFile(result.filePath, exePath);
installer.start(exePath.toString(), {"/passive"});
// Wait for setup to complete
installer.waitForFinished(10 * 60 * 1000);
@@ -2122,7 +2125,7 @@ void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result)
qDebug("Setup should be complete!");
// Delete temp file
Utils::Fs::forceRemove(exePath);
Utils::Fs::removeFile(exePath);
// Reload search engine
if (Utils::ForeignApps::pythonInfo().isSupportedVersion())

View File

@@ -212,7 +212,7 @@ private:
bool event(QEvent *e) override;
void displayRSSTab(bool enable);
void displaySearchTab(bool enable);
void createTorrentTriggered(const QString &path = {});
void createTorrentTriggered(const Path &path);
void showStatusBar(bool show);
Ui::MainWindow *m_ui;

View File

@@ -48,6 +48,7 @@
#include "base/net/dnsupdater.h"
#include "base/net/portforwarder.h"
#include "base/net/proxyconfigurationmanager.h"
#include "base/path.h"
#include "base/preferences.h"
#include "base/rss/rss_autodownloader.h"
#include "base/rss/rss_session.h"
@@ -492,9 +493,9 @@ OptionsDialog::OptionsDialog(QWidget *parent)
connect(m_ui->checkWebUIUPnP, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkWebUiHttps, &QGroupBox::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, [this](const QString &s) { webUIHttpsCertChanged(s, ShowError::Show); });
connect(m_ui->textWebUIHttpsCert, &FileSystemPathLineEdit::selectedPathChanged, this, [this](const Path &path) { webUIHttpsCertChanged(path, ShowError::Show); });
connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, &ThisType::enableApplyButton);
connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, [this](const QString &s) { webUIHttpsKeyChanged(s, ShowError::Show); });
connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, [this](const Path &path) { webUIHttpsKeyChanged(path, ShowError::Show); });
connect(m_ui->textWebUiUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
connect(m_ui->textWebUiPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton);
connect(m_ui->checkBypassLocalAuth, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
@@ -732,7 +733,7 @@ void OptionsDialog::saveOptions()
auto session = BitTorrent::Session::instance();
// Downloads preferences
session->setSavePath(Utils::Fs::expandPathAbs(m_ui->textSavePath->selectedPath()));
session->setSavePath(Path(m_ui->textSavePath->selectedPath()));
session->setSubcategoriesEnabled(m_ui->checkUseSubcategories->isChecked());
session->setUseCategoryPathsInManualMode(m_ui->checkUseCategoryPaths->isChecked());
session->setAutoTMMDisabledByDefault(m_ui->comboSavingMode->currentIndex() == 0);
@@ -740,7 +741,7 @@ void OptionsDialog::saveOptions()
session->setDisableAutoTMMWhenCategorySavePathChanged(m_ui->comboCategoryChanged->currentIndex() == 1);
session->setDisableAutoTMMWhenDefaultSavePathChanged(m_ui->comboCategoryDefaultPathChanged->currentIndex() == 1);
session->setDownloadPathEnabled(m_ui->checkUseDownloadPath->isChecked());
session->setDownloadPath(Utils::Fs::expandPathAbs(m_ui->textDownloadPath->selectedPath()));
session->setDownloadPath(m_ui->textDownloadPath->selectedPath());
session->setAppendExtensionEnabled(m_ui->checkAppendqB->isChecked());
session->setPreallocationEnabled(preAllocateAllFiles());
pref->disableRecursiveDownload(!m_ui->checkRecursiveDownload->isChecked());
@@ -1008,14 +1009,12 @@ void OptionsDialog::loadOptions()
m_ui->comboCategoryDefaultPathChanged->setCurrentIndex(session->isDisableAutoTMMWhenDefaultSavePathChanged());
m_ui->checkUseDownloadPath->setChecked(session->isDownloadPathEnabled());
m_ui->textDownloadPath->setEnabled(m_ui->checkUseDownloadPath->isChecked());
m_ui->textDownloadPath->setEnabled(m_ui->checkUseDownloadPath->isChecked());
m_ui->textDownloadPath->setSelectedPath(Utils::Fs::toNativePath(session->downloadPath()));
m_ui->textDownloadPath->setSelectedPath(session->downloadPath());
m_ui->checkAppendqB->setChecked(session->isAppendExtensionEnabled());
m_ui->checkPreallocateAll->setChecked(session->isPreallocationEnabled());
m_ui->checkRecursiveDownload->setChecked(!pref->recursiveDownloadDisabled());
strValue = session->torrentExportDirectory();
if (strValue.isEmpty())
if (session->torrentExportDirectory().isEmpty())
{
// Disable
m_ui->checkExportDir->setChecked(false);
@@ -1026,11 +1025,10 @@ void OptionsDialog::loadOptions()
// Enable
m_ui->checkExportDir->setChecked(true);
m_ui->textExportDir->setEnabled(true);
m_ui->textExportDir->setSelectedPath(strValue);
m_ui->textExportDir->setSelectedPath(session->torrentExportDirectory());
}
strValue = session->finishedTorrentExportDirectory();
if (strValue.isEmpty())
if (session->finishedTorrentExportDirectory().isEmpty())
{
// Disable
m_ui->checkExportDirFin->setChecked(false);
@@ -1041,7 +1039,7 @@ void OptionsDialog::loadOptions()
// Enable
m_ui->checkExportDirFin->setChecked(true);
m_ui->textExportDirFin->setEnabled(true);
m_ui->textExportDirFin->setSelectedPath(strValue);
m_ui->textExportDirFin->setSelectedPath(session->finishedTorrentExportDirectory());
}
m_ui->groupMailNotification->setChecked(pref->isMailNotificationEnabled());
@@ -1644,25 +1642,25 @@ void OptionsDialog::setLocale(const QString &localeStr)
m_ui->comboI18n->setCurrentIndex(index);
}
QString OptionsDialog::getTorrentExportDir() const
Path OptionsDialog::getTorrentExportDir() const
{
if (m_ui->checkExportDir->isChecked())
return Utils::Fs::expandPathAbs(m_ui->textExportDir->selectedPath());
return m_ui->textExportDir->selectedPath();
return {};
}
QString OptionsDialog::getFinishedTorrentExportDir() const
Path OptionsDialog::getFinishedTorrentExportDir() const
{
if (m_ui->checkExportDirFin->isChecked())
return Utils::Fs::expandPathAbs(m_ui->textExportDirFin->selectedPath());
return m_ui->textExportDirFin->selectedPath();
return {};
}
void OptionsDialog::on_addWatchedFolderButton_clicked()
{
Preferences *const pref = Preferences::instance();
const QString dir = QFileDialog::getExistingDirectory(this, tr("Select folder to monitor"),
Utils::Fs::toNativePath(Utils::Fs::folderName(pref->getScanDirsLastPath())));
const Path dir {QFileDialog::getExistingDirectory(
this, tr("Select folder to monitor"), pref->getScanDirsLastPath().parentPath().toString())};
if (dir.isEmpty())
return;
@@ -1739,19 +1737,8 @@ void OptionsDialog::editWatchedFolderOptions(const QModelIndex &index)
dialog->open();
}
QString OptionsDialog::askForExportDir(const QString &currentExportPath)
{
QDir currentExportDir(Utils::Fs::expandPathAbs(currentExportPath));
QString dir;
if (!currentExportPath.isEmpty() && currentExportDir.exists())
dir = QFileDialog::getExistingDirectory(this, tr("Choose export directory"), currentExportDir.absolutePath());
else
dir = QFileDialog::getExistingDirectory(this, tr("Choose export directory"), QDir::homePath());
return dir;
}
// Return Filter object to apply to BT session
QString OptionsDialog::getFilter() const
Path OptionsDialog::getFilter() const
{
return m_ui->textFilterPath->selectedPath();
}
@@ -1773,7 +1760,7 @@ QString OptionsDialog::webUiPassword() const
return m_ui->textWebUiPassword->text();
}
void OptionsDialog::webUIHttpsCertChanged(const QString &path, const ShowError showError)
void OptionsDialog::webUIHttpsCertChanged(const Path &path, const ShowError showError)
{
m_ui->textWebUIHttpsCert->setSelectedPath(path);
m_ui->lblSslCertStatus->setPixmap(Utils::Gui::scaledPixmapSvg(UIThemeManager::instance()->getIconPath(QLatin1String("security-low")), this, 24));
@@ -1781,7 +1768,7 @@ void OptionsDialog::webUIHttpsCertChanged(const QString &path, const ShowError s
if (path.isEmpty())
return;
QFile file(path);
QFile file {path.data()};
if (!file.open(QIODevice::ReadOnly))
{
if (showError == ShowError::Show)
@@ -1799,7 +1786,7 @@ void OptionsDialog::webUIHttpsCertChanged(const QString &path, const ShowError s
m_ui->lblSslCertStatus->setPixmap(Utils::Gui::scaledPixmapSvg(UIThemeManager::instance()->getIconPath(QLatin1String("security-high")), this, 24));
}
void OptionsDialog::webUIHttpsKeyChanged(const QString &path, const ShowError showError)
void OptionsDialog::webUIHttpsKeyChanged(const Path &path, const ShowError showError)
{
m_ui->textWebUIHttpsKey->setSelectedPath(path);
m_ui->lblSslKeyStatus->setPixmap(Utils::Gui::scaledPixmapSvg(UIThemeManager::instance()->getIconPath(QLatin1String("security-low")), this, 24));
@@ -1807,7 +1794,7 @@ void OptionsDialog::webUIHttpsKeyChanged(const QString &path, const ShowError sh
if (path.isEmpty())
return;
QFile file(path);
QFile file {path.data()};
if (!file.open(QIODevice::ReadOnly))
{
if (showError == ShowError::Show)
@@ -1843,7 +1830,7 @@ void OptionsDialog::on_IpFilterRefreshBtn_clicked()
// Updating program preferences
BitTorrent::Session *const session = BitTorrent::Session::instance();
session->setIPFilteringEnabled(true);
session->setIPFilterFile(""); // forcing Session reload filter file
session->setIPFilterFile({}); // forcing Session reload filter file
session->setIPFilterFile(getFilter());
connect(session, &BitTorrent::Session::IPFilterParsed, this, &OptionsDialog::handleIPFilterParsed);
setCursor(QCursor(Qt::WaitCursor));
@@ -1887,7 +1874,7 @@ bool OptionsDialog::webUIAuthenticationOk()
bool OptionsDialog::isAlternativeWebUIPathValid()
{
if (m_ui->groupAltWebUI->isChecked() && m_ui->textWebUIRootFolder->selectedPath().trimmed().isEmpty())
if (m_ui->groupAltWebUI->isChecked() && m_ui->textWebUIRootFolder->selectedPath().isEmpty())
{
QMessageBox::warning(this, tr("Location Error"), tr("The alternative Web UI files location cannot be blank."));
return false;

View File

@@ -30,6 +30,7 @@
#include <QDialog>
#include "base/pathfwd.h"
#include "base/settingvalue.h"
class QCloseEvent;
@@ -112,8 +113,8 @@ private slots:
void on_removeWatchedFolderButton_clicked();
void on_registerDNSBtn_clicked();
void setLocale(const QString &localeStr);
void webUIHttpsCertChanged(const QString &path, ShowError showError);
void webUIHttpsKeyChanged(const QString &path, ShowError showError);
void webUIHttpsCertChanged(const Path &path, ShowError showError);
void webUIHttpsKeyChanged(const Path &path, ShowError showError);
private:
// Methods
@@ -136,9 +137,8 @@ private:
bool preAllocateAllFiles() const;
bool useAdditionDialog() const;
bool addTorrentsInPause() const;
QString getTorrentExportDir() const;
QString getFinishedTorrentExportDir() const;
QString askForExportDir(const QString &currentExportPath);
Path getTorrentExportDir() const;
Path getFinishedTorrentExportDir() const;
// Connection options
int getPort() const;
bool isUPnPEnabled() const;
@@ -162,7 +162,7 @@ private:
Net::ProxyType getProxyType() const;
// IP Filter
bool isIPFilteringEnabled() const;
QString getFilter() const;
Path getFilter() const;
// Queueing system
bool isQueueingSystemEnabled() const;
int getMaxActiveDownloads() const;

View File

@@ -93,12 +93,12 @@ PreviewSelectDialog::PreviewSelectDialog(QWidget *parent, const BitTorrent::Torr
const QVector<qreal> fp = torrent->filesProgress();
for (int i = 0; i < torrent->filesCount(); ++i)
{
const QString fileName = Utils::Fs::fileName(torrent->filePath(i));
if (Utils::Misc::isPreviewable(fileName))
const Path filePath = torrent->filePath(i);
if (Utils::Misc::isPreviewable(filePath))
{
int row = m_previewListModel->rowCount();
m_previewListModel->insertRow(row);
m_previewListModel->setData(m_previewListModel->index(row, NAME), fileName);
m_previewListModel->setData(m_previewListModel->index(row, NAME), filePath.filename());
m_previewListModel->setData(m_previewListModel->index(row, SIZE), torrent->fileSize(i));
m_previewListModel->setData(m_previewListModel->index(row, PROGRESS), fp[i]);
m_previewListModel->setData(m_previewListModel->index(row, FILE_INDEX), i);
@@ -133,14 +133,14 @@ void PreviewSelectDialog::previewButtonClicked()
// Only one file should be selected
const int fileIndex = selectedIndexes.at(0).data().toInt();
const QString path = QDir(m_torrent->actualStorageLocation()).absoluteFilePath(m_torrent->actualFilePath(fileIndex));
const Path path = m_torrent->actualStorageLocation() / m_torrent->actualFilePath(fileIndex);
// File
if (!QFile::exists(path))
if (!path.exists())
{
const bool isSingleFile = (m_previewListModel->rowCount() == 1);
QWidget *parent = isSingleFile ? this->parentWidget() : this;
QMessageBox::critical(parent, tr("Preview impossible")
, tr("Sorry, we can't preview this file: \"%1\".").arg(Utils::Fs::toNativePath(path)));
, tr("Sorry, we can't preview this file: \"%1\".").arg(path.toString()));
if (isSingleFile)
reject();
return;

View File

@@ -30,6 +30,7 @@
#include <QDialog>
#include "base/path.h"
#include "base/settingvalue.h"
class QStandardItemModel;
@@ -38,6 +39,7 @@ namespace BitTorrent
{
class Torrent;
}
namespace Ui
{
class PreviewSelectDialog;
@@ -64,7 +66,7 @@ public:
~PreviewSelectDialog();
signals:
void readyToPreviewFile(QString) const;
void readyToPreviewFile(const Path &filePath) const;
private slots:
void previewButtonClicked();

View File

@@ -470,9 +470,11 @@ void PeerListWidget::updatePeer(const BitTorrent::Torrent *torrent, const BitTor
setModelData(row, PeerListColumns::TOT_UP, totalUp, peer.totalUpload(), intDataTextAlignment);
setModelData(row, PeerListColumns::RELEVANCE, (Utils::String::fromDouble(peer.relevance() * 100, 1) + '%'), peer.relevance(), intDataTextAlignment);
const QStringList downloadingFiles {torrent->hasMetadata()
? torrent->info().filesForPiece(peer.downloadingPieceIndex())
: QStringList()};
const PathList filePaths = torrent->info().filesForPiece(peer.downloadingPieceIndex());
QStringList downloadingFiles;
downloadingFiles.reserve(filePaths.size());
for (const Path &filePath : filePaths)
downloadingFiles.append(filePath.toString());
const QString downloadingFilesDisplayValue = downloadingFiles.join(';');
setModelData(row, PeerListColumns::DOWNLOADING_PIECE, downloadingFilesDisplayValue, downloadingFilesDisplayValue, {}, downloadingFiles.join(QLatin1Char('\n')));

View File

@@ -37,9 +37,10 @@
#include <QTextStream>
#include <QToolTip>
#include "base/indexrange.h"
#include "base/bittorrent/torrent.h"
#include "base/bittorrent/torrentinfo.h"
#include "base/indexrange.h"
#include "base/path.h"
#include "base/utils/misc.h"
namespace
@@ -53,9 +54,8 @@ namespace
{
public:
PieceIndexToImagePos(const BitTorrent::TorrentInfo &torrentInfo, const QImage &image)
: m_bytesPerPixel
{((image.width() > 0) && (torrentInfo.totalSize() >= image.width()))
? torrentInfo.totalSize() / image.width() : -1}
: m_bytesPerPixel {((image.width() > 0) && (torrentInfo.totalSize() >= image.width()))
? torrentInfo.totalSize() / image.width() : -1}
, m_torrentInfo {torrentInfo}
{
if ((m_bytesPerPixel > 0) && (m_bytesPerPixel < 10))
@@ -100,9 +100,9 @@ namespace
m_stream << "</table>";
}
void operator()(const QString &size, const QString &path)
void operator()(const QString &size, const Path &path)
{
m_stream << R"(<tr><td style="white-space:nowrap">)" << size << "</td><td>" << path << "</td></tr>";
m_stream << R"(<tr><td style="white-space:nowrap">)" << size << "</td><td>" << path.toString() << "</td></tr>";
}
private:
@@ -282,7 +282,7 @@ void PiecesBar::showToolTip(const QHelpEvent *e)
for (int f : files)
{
const QString filePath {torrentInfo.filePath(f)};
const Path filePath = torrentInfo.filePath(f);
renderer(Utils::Misc::friendlyUnit(torrentInfo.fileSize(f)), filePath);
}
stream << "</body></html>";

View File

@@ -31,7 +31,6 @@
#include <QClipboard>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QHeaderView>
#include <QListWidgetItem>
#include <QMenu>
@@ -45,6 +44,7 @@
#include "base/bittorrent/infohash.h"
#include "base/bittorrent/session.h"
#include "base/bittorrent/torrent.h"
#include "base/path.h"
#include "base/preferences.h"
#include "base/unicodestrings.h"
#include "base/utils/fs.h"
@@ -333,7 +333,7 @@ QTreeView *PropertiesWidget::getFilesList() const
void PropertiesWidget::updateSavePath(BitTorrent::Torrent *const torrent)
{
if (torrent == m_torrent)
m_ui->labelSavePathVal->setText(Utils::Fs::toNativePath(m_torrent->savePath()));
m_ui->labelSavePathVal->setText(m_torrent->savePath().toString());
}
void PropertiesWidget::loadTrackers(BitTorrent::Torrent *const torrent)
@@ -593,25 +593,22 @@ void PropertiesWidget::loadUrlSeeds()
}
}
QString PropertiesWidget::getFullPath(const QModelIndex &index) const
Path PropertiesWidget::getFullPath(const QModelIndex &index) const
{
const QDir saveDir {m_torrent->actualStorageLocation()};
if (m_propListModel->itemType(index) == TorrentContentModelItem::FileType)
{
const int fileIdx = m_propListModel->getFileIndex(index);
const QString filename {m_torrent->actualFilePath(fileIdx)};
const QString fullPath {Utils::Fs::expandPath(saveDir.absoluteFilePath(filename))};
const Path fullPath = m_torrent->actualStorageLocation() / m_torrent->actualFilePath(fileIdx);
return fullPath;
}
// folder type
const QModelIndex nameIndex {index.sibling(index.row(), TorrentContentModelItem::COL_NAME)};
QString folderPath {nameIndex.data().toString()};
Path folderPath {nameIndex.data().toString()};
for (QModelIndex modelIdx = m_propListModel->parent(nameIndex); modelIdx.isValid(); modelIdx = modelIdx.parent())
folderPath.prepend(modelIdx.data().toString() + '/');
folderPath = Path(modelIdx.data().toString()) / folderPath;
const QString fullPath {Utils::Fs::expandPath(saveDir.absoluteFilePath(folderPath))};
const Path fullPath = m_torrent->actualStorageLocation() / folderPath;
return fullPath;
}
@@ -626,7 +623,7 @@ void PropertiesWidget::openItem(const QModelIndex &index) const
void PropertiesWidget::openParentFolder(const QModelIndex &index) const
{
const QString path = getFullPath(index);
const Path path = getFullPath(index);
m_torrent->flushCache(); // Flush data
#ifdef Q_OS_MACOS
MacUtils::openFiles({path});

View File

@@ -31,6 +31,8 @@
#include <QList>
#include <QWidget>
#include "base/pathfwd.h"
class QPushButton;
class QTreeView;
@@ -108,7 +110,7 @@ private:
QPushButton *getButtonFromIndex(int index);
void applyPriorities();
void openParentFolder(const QModelIndex &index) const;
QString getFullPath(const QModelIndex &index) const;
Path getFullPath(const QModelIndex &index) const;
Ui::PropertiesWidget *m_ui;
BitTorrent::Torrent *m_torrent;

View File

@@ -40,6 +40,7 @@
#include "base/bittorrent/session.h"
#include "base/global.h"
#include "base/path.h"
#include "base/preferences.h"
#include "base/rss/rss_article.h"
#include "base/rss/rss_autodownloader.h"
@@ -47,7 +48,6 @@
#include "base/rss/rss_folder.h"
#include "base/rss/rss_session.h"
#include "base/utils/compare.h"
#include "base/utils/fs.h"
#include "base/utils/io.h"
#include "base/utils/string.h"
#include "gui/autoexpandabledialog.h"
@@ -261,7 +261,7 @@ void AutomatedRssDownloader::updateRuleDefinitionBox()
else
m_ui->lineEFilter->clear();
m_ui->checkBoxSaveDiffDir->setChecked(!m_currentRule.savePath().isEmpty());
m_ui->lineSavePath->setSelectedPath(Utils::Fs::toNativePath(m_currentRule.savePath()));
m_ui->lineSavePath->setSelectedPath(m_currentRule.savePath());
m_ui->checkRegex->blockSignals(true);
m_ui->checkRegex->setChecked(m_currentRule.useRegex());
m_ui->checkRegex->blockSignals(false);
@@ -346,7 +346,7 @@ void AutomatedRssDownloader::updateEditedRule()
m_currentRule.setMustContain(m_ui->lineContains->text());
m_currentRule.setMustNotContain(m_ui->lineNotContains->text());
m_currentRule.setEpisodeFilter(m_ui->lineEFilter->text());
m_currentRule.setSavePath(m_ui->checkBoxSaveDiffDir->isChecked() ? m_ui->lineSavePath->selectedPath() : "");
m_currentRule.setSavePath(m_ui->checkBoxSaveDiffDir->isChecked() ? m_ui->lineSavePath->selectedPath() : Path());
m_currentRule.setCategory(m_ui->comboCategory->currentText());
std::optional<bool> addPaused;
if (m_ui->comboAddPaused->currentIndex() == 1)
@@ -429,9 +429,10 @@ void AutomatedRssDownloader::on_exportBtn_clicked()
}
QString selectedFilter {m_formatFilterJSON};
QString path = QFileDialog::getSaveFileName(
Path path {QFileDialog::getSaveFileName(
this, tr("Export RSS rules"), QDir::homePath()
, QString::fromLatin1("%1;;%2").arg(m_formatFilterJSON, m_formatFilterLegacy), &selectedFilter);
, QString::fromLatin1("%1;;%2").arg(m_formatFilterJSON, m_formatFilterLegacy), &selectedFilter)};
if (path.isEmpty()) return;
const RSS::AutoDownloader::RulesFileFormat format
@@ -443,12 +444,12 @@ void AutomatedRssDownloader::on_exportBtn_clicked()
if (format == RSS::AutoDownloader::RulesFileFormat::JSON)
{
if (!path.endsWith(EXT_JSON, Qt::CaseInsensitive))
if (!path.hasExtension(EXT_JSON))
path += EXT_JSON;
}
else
{
if (!path.endsWith(EXT_LEGACY, Qt::CaseInsensitive))
if (!path.hasExtension(EXT_LEGACY))
path += EXT_LEGACY;
}
@@ -464,13 +465,13 @@ void AutomatedRssDownloader::on_exportBtn_clicked()
void AutomatedRssDownloader::on_importBtn_clicked()
{
QString selectedFilter {m_formatFilterJSON};
QString path = QFileDialog::getOpenFileName(
this, tr("Import RSS rules"), QDir::homePath()
, QString::fromLatin1("%1;;%2").arg(m_formatFilterJSON, m_formatFilterLegacy), &selectedFilter);
if (path.isEmpty() || !QFile::exists(path))
const Path path {QFileDialog::getOpenFileName(
this, tr("Import RSS rules"), QDir::homePath()
, QString::fromLatin1("%1;;%2").arg(m_formatFilterJSON, m_formatFilterLegacy), &selectedFilter)};
if (!path.exists())
return;
QFile file {path};
QFile file {path.data()};
if (!file.open(QIODevice::ReadOnly))
{
QMessageBox::critical(

View File

@@ -67,9 +67,9 @@ namespace
}
};
QIcon loadIcon(const QString &path, const QString &fallbackId)
QIcon loadIcon(const Path &path, const QString &fallbackId)
{
const QPixmap pixmap {path};
const QPixmap pixmap {path.data()};
if (!pixmap.isNull())
return {pixmap};

View File

@@ -30,7 +30,6 @@
#include <QApplication>
#include <QDateTime>
#include <QDir>
#include <QDebug>
#include <QNetworkDiskCache>
#include <QNetworkReply>
@@ -38,6 +37,7 @@
#include <QScrollBar>
#include <QStyle>
#include "base/path.h"
#include "base/profile.h"
HtmlBrowser::HtmlBrowser(QWidget *parent)
@@ -45,7 +45,7 @@ HtmlBrowser::HtmlBrowser(QWidget *parent)
{
m_netManager = new QNetworkAccessManager(this);
m_diskCache = new QNetworkDiskCache(this);
m_diskCache->setCacheDirectory(QDir::cleanPath(specialFolderLocation(SpecialFolder::Cache) + "/rss"));
m_diskCache->setCacheDirectory((specialFolderLocation(SpecialFolder::Cache) / Path("rss")).data());
m_diskCache->setMaximumCacheSize(50 * 1024 * 1024);
qDebug() << "HtmlBrowser cache path:" << m_diskCache->cacheDirectory() << " max size:" << m_diskCache->maximumCacheSize() / 1024 / 1024 << "MB";
m_netManager->setCache(m_diskCache);

View File

@@ -309,10 +309,10 @@ void PluginSelectDialog::addNewPlugin(const QString &pluginName)
setRowColor(m_ui->pluginsTree->indexOfTopLevelItem(item), "red");
}
// Handle icon
if (QFile::exists(plugin->iconPath))
if (plugin->iconPath.exists())
{
// Good, we already have the icon
item->setData(PLUGIN_NAME, Qt::DecorationRole, QIcon(plugin->iconPath));
item->setData(PLUGIN_NAME, Qt::DecorationRole, QIcon(plugin->iconPath.data()));
}
else
{
@@ -406,10 +406,10 @@ void PluginSelectDialog::iconDownloadFinished(const Net::DownloadResult &result)
return;
}
const QString filePath = Utils::Fs::toUniformPath(result.filePath);
const Path filePath = result.filePath;
// Icon downloaded
QIcon icon(filePath);
QIcon icon {filePath.data()};
// Detect a non-decodable icon
QList<QSize> sizes = icon.availableSizes();
bool invalid = (sizes.isEmpty() || icon.pixmap(sizes.first()).isNull());
@@ -421,21 +421,19 @@ void PluginSelectDialog::iconDownloadFinished(const Net::DownloadResult &result)
PluginInfo *plugin = m_pluginManager->pluginInfo(id);
if (!plugin) continue;
QString iconPath = QString("%1/%2.%3")
.arg(SearchPluginManager::pluginsLocation()
, id
, result.url.endsWith(".ico", Qt::CaseInsensitive) ? "ico" : "png");
if (QFile::copy(filePath, iconPath))
const QString ext = result.url.endsWith(QLatin1String(".ico"), Qt::CaseInsensitive) ? QLatin1String(".ico") : QLatin1String(".png");
const Path iconPath = SearchPluginManager::pluginsLocation() / Path(id + ext);
if (Utils::Fs::copyFile(filePath, iconPath))
{
// This 2nd check is necessary. Some favicons (eg from piratebay)
// decode fine without an ext, but fail to do so when appending the ext
// from the url. Probably a Qt bug.
QIcon iconWithExt(iconPath);
QIcon iconWithExt {iconPath.data()};
QList<QSize> sizesExt = iconWithExt.availableSizes();
bool invalidExt = (sizesExt.isEmpty() || iconWithExt.pixmap(sizesExt.first()).isNull());
if (invalidExt)
{
Utils::Fs::forceRemove(iconPath);
Utils::Fs::removeFile(iconPath);
continue;
}
@@ -445,7 +443,7 @@ void PluginSelectDialog::iconDownloadFinished(const Net::DownloadResult &result)
}
}
// Delete tmp file
Utils::Fs::forceRemove(filePath);
Utils::Fs::removeFile(filePath);
}
void PluginSelectDialog::checkForUpdatesFinished(const QHash<QString, PluginVersion> &updateInfo)

View File

@@ -153,7 +153,7 @@ void TorrentCategoryDialog::setCategoryOptions(const BitTorrent::CategoryOptions
if (categoryOptions.downloadPath)
{
m_ui->comboUseDownloadPath->setCurrentIndex(categoryOptions.downloadPath->enabled ? 1 : 2);
m_ui->comboDownloadPath->setSelectedPath(categoryOptions.downloadPath->enabled ? categoryOptions.downloadPath->path : QString());
m_ui->comboDownloadPath->setSelectedPath(categoryOptions.downloadPath->enabled ? categoryOptions.downloadPath->path : Path());
}
else
{
@@ -164,30 +164,29 @@ void TorrentCategoryDialog::setCategoryOptions(const BitTorrent::CategoryOptions
void TorrentCategoryDialog::categoryNameChanged(const QString &categoryName)
{
const QString categoryPath = Utils::Fs::toValidFileSystemName(categoryName, true);
const Path categoryPath = Utils::Fs::toValidPath(categoryName);
const auto *btSession = BitTorrent::Session::instance();
m_ui->comboSavePath->setPlaceholder(Utils::Fs::resolvePath(categoryPath, btSession->savePath()));
m_ui->comboSavePath->setPlaceholder(btSession->savePath() / categoryPath);
const int index = m_ui->comboUseDownloadPath->currentIndex();
const bool useDownloadPath = (index == 1) || ((index == 0) && BitTorrent::Session::instance()->isDownloadPathEnabled());
if (useDownloadPath)
m_ui->comboDownloadPath->setPlaceholder(Utils::Fs::resolvePath(categoryPath, btSession->downloadPath()));
m_ui->comboDownloadPath->setPlaceholder(btSession->downloadPath() / categoryPath);
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!categoryName.isEmpty());
}
void TorrentCategoryDialog::useDownloadPathChanged(const int index)
{
if (const QString selectedPath = m_ui->comboDownloadPath->selectedPath(); !selectedPath.isEmpty())
if (const Path selectedPath = m_ui->comboDownloadPath->selectedPath(); !selectedPath.isEmpty())
m_lastEnteredDownloadPath = selectedPath;
m_ui->labelDownloadPath->setEnabled(index == 1);
m_ui->comboDownloadPath->setEnabled(index == 1);
m_ui->comboDownloadPath->setSelectedPath((index == 1) ? m_lastEnteredDownloadPath : QString());
m_ui->comboDownloadPath->setSelectedPath((index == 1) ? m_lastEnteredDownloadPath : Path());
const QString categoryName = m_ui->textCategoryName->text();
const QString categoryPath = Utils::Fs::resolvePath(Utils::Fs::toValidFileSystemName(categoryName, true)
, BitTorrent::Session::instance()->downloadPath());
const Path categoryPath = BitTorrent::Session::instance()->downloadPath() / Utils::Fs::toValidPath(categoryName);
const bool useDownloadPath = (index == 1) || ((index == 0) && BitTorrent::Session::instance()->isDownloadPathEnabled());
m_ui->comboDownloadPath->setPlaceholder(useDownloadPath ? categoryPath : QString());
m_ui->comboDownloadPath->setPlaceholder(useDownloadPath ? categoryPath : Path());
}

View File

@@ -30,6 +30,8 @@
#include <QDialog>
#include "base/path.h"
namespace BitTorrent
{
struct CategoryOptions;
@@ -64,5 +66,5 @@ private slots:
private:
Ui::TorrentCategoryDialog *m_ui;
QString m_lastEnteredDownloadPath;
Path m_lastEnteredDownloadPath;
};

View File

@@ -53,6 +53,7 @@
#include "base/bittorrent/abstractfilestorage.h"
#include "base/bittorrent/downloadpriority.h"
#include "base/global.h"
#include "base/path.h"
#include "base/utils/fs.h"
#include "torrentcontentmodelfile.h"
#include "torrentcontentmodelfolder.h"
@@ -503,7 +504,7 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
for (int i = 0; i < filesCount; ++i)
{
currentParent = m_rootItem;
const QString path = Utils::Fs::toUniformPath(info.filePath(i));
const QString path = info.filePath(i).data();
// Iterate of parts of the path to create necessary folders
QList<QStringView> pathFolders = QStringView(path).split(u'/', Qt::SkipEmptyParts);
@@ -523,7 +524,7 @@ void TorrentContentModel::setupModelData(const BitTorrent::AbstractFileStorage &
}
// Actually create the file
TorrentContentModelFile *fileItem = new TorrentContentModelFile(
Utils::Fs::fileName(info.filePath(i)), info.fileSize(i), currentParent, i);
info.filePath(i).filename(), info.fileSize(i), currentParent, i);
currentParent->appendChild(fileItem);
m_filesIndex.push_back(fileItem);
}

View File

@@ -44,6 +44,7 @@
#include "base/bittorrent/torrentinfo.h"
#include "base/exceptions.h"
#include "base/global.h"
#include "base/path.h"
#include "base/utils/fs.h"
#include "autoexpandabledialog.h"
#include "raisedmessagebox.h"
@@ -52,12 +53,12 @@
namespace
{
QString getFullPath(const QModelIndex &idx)
Path getFullPath(const QModelIndex &idx)
{
QStringList paths;
Path path;
for (QModelIndex i = idx; i.isValid(); i = i.parent())
paths.prepend(i.data().toString());
return paths.join(QLatin1Char {'/'});
path = Path(i.data().toString()) / path;
return path;
}
}
@@ -130,9 +131,9 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::AbstractFileStorage
if (newName == oldName)
return; // Name did not change
const QString parentPath = getFullPath(modelIndex.parent());
const QString oldPath {parentPath.isEmpty() ? oldName : parentPath + QLatin1Char {'/'} + oldName};
const QString newPath {parentPath.isEmpty() ? newName : parentPath + QLatin1Char {'/'} + newName};
const Path parentPath = getFullPath(modelIndex.parent());
const Path oldPath = parentPath / Path(oldName);
const Path newPath = parentPath / Path(newName);
try
{

View File

@@ -44,7 +44,7 @@
#define SETTINGS_KEY(name) "TorrentCreator/" name
TorrentCreatorDialog::TorrentCreatorDialog(QWidget *parent, const QString &defaultPath)
TorrentCreatorDialog::TorrentCreatorDialog(QWidget *parent, const Path &defaultPath)
: QDialog(parent)
, m_ui(new Ui::TorrentCreatorDialog)
, m_creatorThread(new BitTorrent::TorrentCreatorThread(this))
@@ -100,24 +100,24 @@ TorrentCreatorDialog::~TorrentCreatorDialog()
delete m_ui;
}
void TorrentCreatorDialog::updateInputPath(const QString &path)
void TorrentCreatorDialog::updateInputPath(const Path &path)
{
if (path.isEmpty()) return;
m_ui->textInputPath->setText(Utils::Fs::toNativePath(path));
m_ui->textInputPath->setText(path.toString());
updateProgressBar(0);
}
void TorrentCreatorDialog::onAddFolderButtonClicked()
{
QString oldPath = m_ui->textInputPath->text();
QString path = QFileDialog::getExistingDirectory(this, tr("Select folder"), oldPath);
const QString oldPath = m_ui->textInputPath->text();
const Path path {QFileDialog::getExistingDirectory(this, tr("Select folder"), oldPath)};
updateInputPath(path);
}
void TorrentCreatorDialog::onAddFileButtonClicked()
{
QString oldPath = m_ui->textInputPath->text();
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), oldPath);
const QString oldPath = m_ui->textInputPath->text();
const Path path {QFileDialog::getOpenFileName(this, tr("Select file"), oldPath)};
updateInputPath(path);
}
@@ -156,9 +156,11 @@ void TorrentCreatorDialog::dropEvent(QDropEvent *event)
if (event->mimeData()->hasUrls())
{
// only take the first one
QUrl firstItem = event->mimeData()->urls().first();
QString path = (firstItem.scheme().compare("file", Qt::CaseInsensitive) == 0)
? firstItem.toLocalFile() : firstItem.toString();
const QUrl firstItem = event->mimeData()->urls().first();
const Path path {
(firstItem.scheme().compare("file", Qt::CaseInsensitive) == 0)
? firstItem.toLocalFile() : firstItem.toString()
};
updateInputPath(path);
}
}
@@ -172,25 +174,23 @@ void TorrentCreatorDialog::dragEnterEvent(QDragEnterEvent *event)
// Main function that create a .torrent file
void TorrentCreatorDialog::onCreateButtonClicked()
{
QString input = Utils::Fs::toUniformPath(m_ui->textInputPath->text()).trimmed();
const auto inputPath = Utils::Fs::toCanonicalPath(Path(m_ui->textInputPath->text().trimmed()));
// test if readable
const QFileInfo fi(input);
if (!fi.isReadable())
if (!Utils::Fs::isReadable(inputPath))
{
QMessageBox::critical(this, tr("Torrent creation failed"), tr("Reason: Path to file/folder is not readable."));
return;
}
input = fi.canonicalFilePath();
// get save path
const QString savePath = m_storeLastSavePath.get(QDir::homePath()) + QLatin1Char('/') + fi.fileName() + QLatin1String(".torrent");
QString destination = QFileDialog::getSaveFileName(this, tr("Select where to save the new torrent"), savePath, tr("Torrent Files (*.torrent)"));
if (destination.isEmpty())
const Path savePath = m_storeLastSavePath.get(Utils::Fs::homePath() / Path(inputPath.filename() + QLatin1String(".torrent")));
Path destPath {QFileDialog::getSaveFileName(this, tr("Select where to save the new torrent"), savePath.data(), tr("Torrent Files (*.torrent)"))};
if (destPath.isEmpty())
return;
if (!destination.endsWith(C_TORRENT_FILE_EXTENSION, Qt::CaseInsensitive))
destination += C_TORRENT_FILE_EXTENSION;
m_storeLastSavePath = Utils::Fs::branchPath(destination);
if (!destPath.hasExtension(C_TORRENT_FILE_EXTENSION))
destPath += C_TORRENT_FILE_EXTENSION;
m_storeLastSavePath = destPath.parentPath();
// Disable dialog & set busy cursor
setInteractionEnabled(false);
@@ -208,7 +208,8 @@ void TorrentCreatorDialog::onCreateButtonClicked()
, getPaddedFileSizeLimit()
#endif
, getPieceSize()
, input, destination
, inputPath
, destPath
, m_ui->txtComment->toPlainText()
, m_ui->lineEditSource->text()
, trackers
@@ -227,14 +228,14 @@ void TorrentCreatorDialog::handleCreationFailure(const QString &msg)
setInteractionEnabled(true);
}
void TorrentCreatorDialog::handleCreationSuccess(const QString &path, const QString &branchPath)
void TorrentCreatorDialog::handleCreationSuccess(const Path &path, const Path &branchPath)
{
// Remove busy cursor
setCursor(QCursor(Qt::ArrowCursor));
if (m_ui->checkStartSeeding->isChecked())
{
// Create save path temp data
const nonstd::expected<BitTorrent::TorrentInfo, QString> result = BitTorrent::TorrentInfo::loadFromFile(Utils::Fs::toNativePath(path));
const nonstd::expected<BitTorrent::TorrentInfo, QString> result = BitTorrent::TorrentInfo::loadFromFile(path);
if (!result)
{
QMessageBox::critical(this, tr("Torrent creation failed"), tr("Reason: Created torrent is invalid. It won't be added to download list."));
@@ -254,7 +255,7 @@ void TorrentCreatorDialog::handleCreationSuccess(const QString &path, const QStr
BitTorrent::Session::instance()->addTorrent(result.value(), params);
}
QMessageBox::information(this, tr("Torrent creator")
, QString::fromLatin1("%1\n%2").arg(tr("Torrent created:"), Utils::Fs::toNativePath(path)));
, QString::fromLatin1("%1\n%2").arg(tr("Torrent created:"), path.toString()));
setInteractionEnabled(true);
}
@@ -265,7 +266,7 @@ void TorrentCreatorDialog::updateProgressBar(int progress)
void TorrentCreatorDialog::updatePiecesCount()
{
const QString path = m_ui->textInputPath->text().trimmed();
const Path path {m_ui->textInputPath->text().trimmed()};
#ifdef QBT_USES_LIBTORRENT2
const int count = BitTorrent::TorrentCreatorThread::calculateTotalPieces(
path, getPieceSize(), getTorrentFormat());
@@ -301,7 +302,7 @@ void TorrentCreatorDialog::setInteractionEnabled(const bool enabled) const
void TorrentCreatorDialog::saveSettings()
{
m_storeLastAddPath = m_ui->textInputPath->text().trimmed();
m_storeLastAddPath = Path(m_ui->textInputPath->text().trimmed());
m_storePieceSize = m_ui->comboPieceSize->currentIndex();
m_storePrivateTorrent = m_ui->checkPrivate->isChecked();
@@ -324,7 +325,7 @@ void TorrentCreatorDialog::saveSettings()
void TorrentCreatorDialog::loadSettings()
{
m_ui->textInputPath->setText(m_storeLastAddPath.get(QDir::homePath()));
m_ui->textInputPath->setText(m_storeLastAddPath.get(Utils::Fs::homePath()).toString());
m_ui->comboPieceSize->setCurrentIndex(m_storePieceSize);
m_ui->checkPrivate->setChecked(m_storePrivateTorrent);

View File

@@ -32,6 +32,7 @@
#include <QDialog>
#include "base/bittorrent/torrentcreatorthread.h"
#include "base/path.h"
#include "base/settingvalue.h"
namespace Ui
@@ -42,11 +43,12 @@ namespace Ui
class TorrentCreatorDialog final : public QDialog
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(TorrentCreatorDialog)
public:
TorrentCreatorDialog(QWidget *parent = nullptr, const QString &defaultPath = {});
TorrentCreatorDialog(QWidget *parent = nullptr, const Path &defaultPath = {});
~TorrentCreatorDialog() override;
void updateInputPath(const QString &path);
void updateInputPath(const Path &path);
private slots:
void updateProgressBar(int progress);
@@ -55,7 +57,7 @@ private slots:
void onAddFileButtonClicked();
void onAddFolderButtonClicked();
void handleCreationFailure(const QString &msg);
void handleCreationSuccess(const QString &path, const QString &branchPath);
void handleCreationSuccess(const Path &path, const Path &branchPath);
private:
void dropEvent(QDropEvent *event) override;
@@ -87,10 +89,10 @@ private:
SettingValue<bool> m_storeOptimizeAlignment;
SettingValue<int> m_paddedFileSizeLimit;
#endif
SettingValue<QString> m_storeLastAddPath;
SettingValue<Path> m_storeLastAddPath;
SettingValue<QString> m_storeTrackerList;
SettingValue<QString> m_storeWebSeedList;
SettingValue<QString> m_storeComments;
SettingValue<QString> m_storeLastSavePath;
SettingValue<Path> m_storeLastSavePath;
SettingValue<QString> m_storeSource;
};

View File

@@ -90,8 +90,8 @@ TorrentOptionsDialog::TorrentOptionsDialog(QWidget *parent, const QVector<BitTor
bool allSameDownloadPath = true;
const bool isFirstTorrentAutoTMMEnabled = torrents[0]->isAutoTMMEnabled();
const QString firstTorrentSavePath = torrents[0]->savePath();
const QString firstTorrentDownloadPath = torrents[0]->downloadPath();
const Path firstTorrentSavePath = torrents[0]->savePath();
const Path firstTorrentDownloadPath = torrents[0]->downloadPath();
const QString firstTorrentCategory = torrents[0]->category();
const int firstTorrentUpLimit = std::max(0, torrents[0]->uploadLimit());
@@ -418,20 +418,20 @@ void TorrentOptionsDialog::accept()
if (m_ui->checkAutoTMM->checkState() == Qt::Unchecked)
{
const QString savePath = m_ui->savePath->selectedPath();
const Path savePath = m_ui->savePath->selectedPath();
if (m_initialValues.savePath != savePath)
torrent->setSavePath(Utils::Fs::expandPathAbs(savePath));
torrent->setSavePath(savePath);
const Qt::CheckState useDownloadPathState = m_ui->checkUseDownloadPath->checkState();
if (useDownloadPathState == Qt::Checked)
{
const QString downloadPath = m_ui->downloadPath->selectedPath();
const Path downloadPath = m_ui->downloadPath->selectedPath();
if (m_initialValues.downloadPath != downloadPath)
torrent->setDownloadPath(Utils::Fs::expandPathAbs(downloadPath));
torrent->setDownloadPath(downloadPath);
}
else if (useDownloadPathState == Qt::Unchecked)
{
torrent->setDownloadPath(QString());
torrent->setDownloadPath({});
}
}
@@ -513,14 +513,14 @@ void TorrentOptionsDialog::handleCategoryChanged(const int index)
{
if (!m_allSameCategory && (m_ui->comboCategory->currentIndex() == 0))
{
m_ui->savePath->setSelectedPath(QString());
m_ui->savePath->setSelectedPath({});
}
else
{
const QString savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->comboCategory->currentText());
m_ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath));
const QString downloadPath = BitTorrent::Session::instance()->categoryDownloadPath(m_ui->comboCategory->currentText());
m_ui->downloadPath->setSelectedPath(Utils::Fs::toNativePath(downloadPath));
const Path savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->comboCategory->currentText());
m_ui->savePath->setSelectedPath(savePath);
const Path downloadPath = BitTorrent::Session::instance()->categoryDownloadPath(m_ui->comboCategory->currentText());
m_ui->downloadPath->setSelectedPath(downloadPath);
m_ui->checkUseDownloadPath->setChecked(!downloadPath.isEmpty());
}
}
@@ -541,8 +541,8 @@ void TorrentOptionsDialog::handleTMMChanged()
if (m_ui->checkAutoTMM->checkState() == Qt::Unchecked)
{
m_ui->groupBoxSavePath->setEnabled(true);
m_ui->savePath->setSelectedPath(Utils::Fs::toNativePath(m_initialValues.savePath));
m_ui->downloadPath->setSelectedPath(Utils::Fs::toNativePath(m_initialValues.downloadPath));
m_ui->savePath->setSelectedPath(m_initialValues.savePath);
m_ui->downloadPath->setSelectedPath(m_initialValues.downloadPath);
m_ui->checkUseDownloadPath->setCheckState(m_initialValues.useDownloadPath);
}
else
@@ -552,23 +552,23 @@ void TorrentOptionsDialog::handleTMMChanged()
{
if (!m_allSameCategory && (m_ui->comboCategory->currentIndex() == 0))
{
m_ui->savePath->setSelectedPath(QString());
m_ui->downloadPath->setSelectedPath(QString());
m_ui->savePath->setSelectedPath({});
m_ui->downloadPath->setSelectedPath({});
m_ui->checkUseDownloadPath->setCheckState(Qt::PartiallyChecked);
}
else
{
const QString savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->comboCategory->currentText());
m_ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath));
const QString downloadPath = BitTorrent::Session::instance()->categoryDownloadPath(m_ui->comboCategory->currentText());
m_ui->downloadPath->setSelectedPath(Utils::Fs::toNativePath(downloadPath));
const Path savePath = BitTorrent::Session::instance()->categorySavePath(m_ui->comboCategory->currentText());
m_ui->savePath->setSelectedPath(savePath);
const Path downloadPath = BitTorrent::Session::instance()->categoryDownloadPath(m_ui->comboCategory->currentText());
m_ui->downloadPath->setSelectedPath(downloadPath);
m_ui->checkUseDownloadPath->setChecked(!downloadPath.isEmpty());
}
}
else // partially checked
{
m_ui->savePath->setSelectedPath(QString());
m_ui->downloadPath->setSelectedPath(QString());
m_ui->savePath->setSelectedPath({});
m_ui->downloadPath->setSelectedPath({});
m_ui->checkUseDownloadPath->setCheckState(Qt::PartiallyChecked);
}
}

View File

@@ -32,6 +32,7 @@
#include <QDialog>
#include "base/path.h"
#include "base/settingvalue.h"
class QAbstractButton;
@@ -82,8 +83,8 @@ private:
QAbstractButton *m_previousRadio = nullptr;
struct
{
QString savePath;
QString downloadPath;
Path savePath;
Path downloadPath;
QString category;
qreal ratio;
int seedingTime;

View File

@@ -322,8 +322,8 @@ TrackerFiltersList::TrackerFiltersList(QWidget *parent, TransferListWidget *tran
TrackerFiltersList::~TrackerFiltersList()
{
for (const QString &iconPath : asConst(m_iconPaths))
Utils::Fs::forceRemove(iconPath);
for (const Path &iconPath : asConst(m_iconPaths))
Utils::Fs::removeFile(iconPath);
}
void TrackerFiltersList::addItem(const QString &tracker, const BitTorrent::TorrentID &id)
@@ -534,14 +534,14 @@ void TrackerFiltersList::handleFavicoDownloadFinished(const Net::DownloadResult
if (!m_trackers.contains(host))
{
Utils::Fs::forceRemove(result.filePath);
Utils::Fs::removeFile(result.filePath);
return;
}
QListWidgetItem *trackerItem = item(rowFromTracker(host));
if (!trackerItem) return;
QIcon icon(result.filePath);
const QIcon icon {result.filePath.data()};
//Detect a non-decodable icon
QList<QSize> sizes = icon.availableSizes();
bool invalid = (sizes.isEmpty() || icon.pixmap(sizes.first()).isNull());
@@ -549,11 +549,11 @@ void TrackerFiltersList::handleFavicoDownloadFinished(const Net::DownloadResult
{
if (result.url.endsWith(".ico", Qt::CaseInsensitive))
downloadFavicon(result.url.left(result.url.size() - 4) + ".png");
Utils::Fs::forceRemove(result.filePath);
Utils::Fs::removeFile(result.filePath);
}
else
{
trackerItem->setData(Qt::DecorationRole, QIcon(result.filePath));
trackerItem->setData(Qt::DecorationRole, QIcon(result.filePath.data()));
m_iconPaths.append(result.filePath);
}
}

View File

@@ -34,6 +34,7 @@
#include "base/bittorrent/infohash.h"
#include "base/bittorrent/trackerentry.h"
#include "base/path.h"
class QCheckBox;
class QResizeEvent;
@@ -133,7 +134,7 @@ private:
QHash<QString, QSet<BitTorrent::TorrentID>> m_trackers; // <tracker host, torrent IDs>
QHash<BitTorrent::TorrentID, QSet<QString>> m_errors; // <torrent ID, tracker hosts>
QHash<BitTorrent::TorrentID, QSet<QString>> m_warnings; // <torrent ID, tracker hosts>
QStringList m_iconPaths;
PathList m_iconPaths;
int m_totalTorrents;
bool m_downloadTrackerFavicon;
};

View File

@@ -392,7 +392,7 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons
case TR_TIME_ELAPSED:
return timeElapsedString(torrent->activeTime(), torrent->finishedTime());
case TR_SAVE_PATH:
return Utils::Fs::toNativePath(torrent->savePath());
return torrent->savePath().toString();
case TR_COMPLETED:
return unitString(torrent->completedSize());
case TR_SEEN_COMPLETE_DATE:
@@ -461,7 +461,7 @@ QVariant TransferListModel::internalValue(const BitTorrent::Torrent *torrent, co
case TR_TIME_ELAPSED:
return !alt ? torrent->activeTime() : torrent->finishedTime();
case TR_SAVE_PATH:
return Utils::Fs::toNativePath(torrent->savePath());
return torrent->savePath().toString();
case TR_COMPLETED:
return torrent->completedSize();
case TR_RATIO_LIMIT:

View File

@@ -90,10 +90,9 @@ namespace
if (!torrent->hasMetadata())
return false;
for (const QString &filePath : asConst(torrent->filePaths()))
for (const Path &filePath : asConst(torrent->filePaths()))
{
const QString fileName = Utils::Fs::fileName(filePath);
if (Utils::Misc::isPreviewable(fileName))
if (Utils::Misc::isPreviewable(filePath))
return true;
}
@@ -243,7 +242,7 @@ TransferListModel *TransferListWidget::getSourceModel() const
return m_listModel;
}
void TransferListWidget::previewFile(const QString &filePath)
void TransferListWidget::previewFile(const Path &filePath)
{
Utils::Gui::openPath(filePath);
}
@@ -336,9 +335,9 @@ void TransferListWidget::setSelectedTorrentsLocation()
if (torrents.isEmpty())
return;
const QString oldLocation = torrents[0]->savePath();
const Path oldLocation = torrents[0]->savePath();
auto fileDialog = new QFileDialog(this, tr("Choose save path"), oldLocation);
auto fileDialog = new QFileDialog(this, tr("Choose save path"), oldLocation.data());
fileDialog->setAttribute(Qt::WA_DeleteOnClose);
fileDialog->setFileMode(QFileDialog::Directory);
fileDialog->setModal(true);
@@ -349,8 +348,8 @@ void TransferListWidget::setSelectedTorrentsLocation()
if (torrents.isEmpty())
return;
const QString newLocation = fileDialog->selectedFiles().constFirst();
if (newLocation.isEmpty() || !QDir(newLocation).exists())
const Path newLocation {fileDialog->selectedFiles().constFirst()};
if (newLocation.exists())
return;
// Actually move storage
@@ -552,28 +551,28 @@ void TransferListWidget::hideQueuePosColumn(bool hide)
void TransferListWidget::openSelectedTorrentsFolder() const
{
QSet<QString> pathsList;
QSet<Path> paths;
#ifdef Q_OS_MACOS
// On macOS you expect both the files and folders to be opened in their parent
// folders prehilighted for opening, so we use a custom method.
for (BitTorrent::Torrent *const torrent : asConst(getSelectedTorrents()))
{
const QString contentPath = QDir(torrent->actualStorageLocation()).absoluteFilePath(torrent->contentPath());
pathsList.insert(contentPath);
const Path contentPath = torrent->actualStorageLocation() / torrent->contentPath();
paths.insert(contentPath);
}
MacUtils::openFiles(pathsList);
MacUtils::openFiles(PathList(paths.cbegin(), paths.cend()));
#else
for (BitTorrent::Torrent *const torrent : asConst(getSelectedTorrents()))
{
const QString contentPath = torrent->contentPath();
if (!pathsList.contains(contentPath))
const Path contentPath = torrent->contentPath();
if (!paths.contains(contentPath))
{
if (torrent->filesCount() == 1)
Utils::Gui::openFolderSelect(contentPath);
else
Utils::Gui::openPath(contentPath);
}
pathsList.insert(contentPath);
paths.insert(contentPath);
}
#endif // Q_OS_MACOS
}

View File

@@ -34,6 +34,7 @@
#include <QTreeView>
#include "base/bittorrent/infohash.h"
#include "base/path.h"
class MainWindow;
class TransferListModel;
@@ -97,7 +98,7 @@ public slots:
void applyTagFilter(const QString &tag);
void applyTrackerFilterAll();
void applyTrackerFilter(const QSet<BitTorrent::TorrentID> &torrentIDs);
void previewFile(const QString &filePath);
void previewFile(const Path &filePath);
void renameSelectedTorrent();
signals:

View File

@@ -38,42 +38,43 @@
#include <QResource>
#include "base/logger.h"
#include "base/path.h"
#include "base/preferences.h"
#include "base/utils/fs.h"
namespace
{
const QString CONFIG_FILE_NAME = QStringLiteral("config.json");
const QString DEFAULT_ICONS_DIR = QStringLiteral(":icons/");
const QString STYLESHEET_FILE_NAME = QStringLiteral("stylesheet.qss");
const Path DEFAULT_ICONS_DIR {":icons"};
const QString CONFIG_FILE_NAME {QStringLiteral("config.json")};
const QString STYLESHEET_FILE_NAME {QStringLiteral("stylesheet.qss")};
// Directory used by stylesheet to reference internal resources
// for example `icon: url(:/uitheme/file.svg)` will be expected to
// point to a file `file.svg` in root directory of CONFIG_FILE_NAME
const QString STYLESHEET_RESOURCES_DIR = QStringLiteral(":/uitheme/");
const QString STYLESHEET_RESOURCES_DIR {QStringLiteral(":/uitheme")};
const QString THEME_ICONS_DIR = QStringLiteral("icons/");
const Path THEME_ICONS_DIR {"icons"};
QString findIcon(const QString &iconId, const QString &dir)
Path findIcon(const QString &iconId, const Path &dir)
{
const QString pathSvg = dir + iconId + QLatin1String(".svg");
if (QFile::exists(pathSvg))
const Path pathSvg = dir / Path(iconId + QLatin1String(".svg"));
if (pathSvg.exists())
return pathSvg;
const QString pathPng = dir + iconId + QLatin1String(".png");
if (QFile::exists(pathPng))
const Path pathPng = dir / Path(iconId + QLatin1String(".png"));
if (pathPng.exists())
return pathPng;
return {};
}
QByteArray readFile(const QString &fileName)
QByteArray readFile(const Path &filePath)
{
QFile file {fileName};
QFile file {filePath.data()};
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
LogMsg(UIThemeManager::tr("UITheme - Failed to open \"%1\". Reason: %2")
.arg(QFileInfo(fileName).fileName(), file.errorString())
.arg(filePath.filename(), file.errorString())
, Log::WARNING);
return {};
}
@@ -86,64 +87,62 @@ namespace
public:
QByteArray readStyleSheet() override
{
return readFile(m_qrcThemeDir + STYLESHEET_FILE_NAME);
return readFile(m_qrcThemeDir / Path(STYLESHEET_FILE_NAME));
}
QByteArray readConfig() override
{
return readFile(m_qrcThemeDir + CONFIG_FILE_NAME);
return readFile(m_qrcThemeDir / Path(CONFIG_FILE_NAME));
}
QString iconPath(const QString &iconId) const override
Path iconPath(const QString &iconId) const override
{
return findIcon(iconId, m_qrcIconsDir);
}
private:
const QString m_qrcThemeDir {":/uitheme/"};
const QString m_qrcIconsDir = m_qrcThemeDir + THEME_ICONS_DIR;
const Path m_qrcThemeDir {":/uitheme"};
const Path m_qrcIconsDir = m_qrcThemeDir / THEME_ICONS_DIR;
};
class FolderThemeSource final : public UIThemeSource
{
public:
explicit FolderThemeSource(const QDir &dir)
: m_folder {dir}
, m_iconsDir {m_folder.absolutePath() + '/' + THEME_ICONS_DIR}
explicit FolderThemeSource(const Path &folderPath)
: m_folder {folderPath}
, m_iconsDir {m_folder / THEME_ICONS_DIR}
{
}
QByteArray readStyleSheet() override
{
QByteArray styleSheetData = readFile(m_folder.absoluteFilePath(STYLESHEET_FILE_NAME));
return styleSheetData.replace(STYLESHEET_RESOURCES_DIR.toUtf8(), (m_folder.absolutePath() + '/').toUtf8());
QByteArray styleSheetData = readFile(m_folder / Path(STYLESHEET_FILE_NAME));
return styleSheetData.replace(STYLESHEET_RESOURCES_DIR.toUtf8(), m_folder.data().toUtf8());
}
QByteArray readConfig() override
{
return readFile(m_folder.absoluteFilePath(CONFIG_FILE_NAME));
return readFile(m_folder / Path(CONFIG_FILE_NAME));
}
QString iconPath(const QString &iconId) const override
Path iconPath(const QString &iconId) const override
{
return findIcon(iconId, m_iconsDir);
}
private:
const QDir m_folder;
const QString m_iconsDir;
const Path m_folder;
const Path m_iconsDir;
};
std::unique_ptr<UIThemeSource> createUIThemeSource(const QString &themePath)
std::unique_ptr<UIThemeSource> createUIThemeSource(const Path &themePath)
{
const QFileInfo themeInfo {themePath};
if (themePath.filename() == CONFIG_FILE_NAME)
return std::make_unique<FolderThemeSource>(themePath);
if (themeInfo.fileName() == CONFIG_FILE_NAME)
return std::make_unique<FolderThemeSource>(themeInfo.dir());
if ((themeInfo.suffix() == QLatin1String {"qbtheme"})
&& QResource::registerResource(themePath, QLatin1String {"/uitheme"}))
if ((themePath.extension() == QLatin1String(".qbtheme"))
&& QResource::registerResource(themePath.data(), QLatin1String("/uitheme")))
{
return std::make_unique<QRCThemeSource>();
}
@@ -174,11 +173,11 @@ UIThemeManager::UIThemeManager()
{
if (m_useCustomTheme)
{
const QString themePath = Preferences::instance()->customUIThemePath();
const Path themePath = Preferences::instance()->customUIThemePath();
m_themeSource = createUIThemeSource(themePath);
if (!m_themeSource)
{
LogMsg(tr("Failed to load UI theme from file: \"%1\"").arg(themePath), Log::WARNING);
LogMsg(tr("Failed to load UI theme from file: \"%1\"").arg(themePath.toString()), Log::WARNING);
}
else
{
@@ -206,7 +205,7 @@ QIcon UIThemeManager::getIcon(const QString &iconId, const QString &fallback) co
{
QIcon icon = QIcon::fromTheme(iconId);
if (icon.name() != iconId)
icon = QIcon::fromTheme(fallback, QIcon(getIconPathFromResources(iconId, fallback)));
icon = QIcon::fromTheme(fallback, QIcon(getIconPathFromResources(iconId, fallback).toString()));
return icon;
}
#endif
@@ -217,7 +216,7 @@ QIcon UIThemeManager::getIcon(const QString &iconId, const QString &fallback) co
if (iter != m_iconCache.end())
return *iter;
const QIcon icon {getIconPathFromResources(iconId, fallback)};
const QIcon icon {getIconPathFromResources(iconId, fallback).data()};
m_iconCache[iconId] = icon;
return icon;
}
@@ -271,17 +270,17 @@ QIcon UIThemeManager::getSystrayIcon() const
}
#endif
QString UIThemeManager::getIconPath(const QString &iconId) const
Path UIThemeManager::getIconPath(const QString &iconId) const
{
#if (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
if (m_useSystemTheme)
{
QString path = Utils::Fs::tempPath() + iconId + QLatin1String(".png");
if (!QFile::exists(path))
Path path = Utils::Fs::tempPath() / Path(iconId + QLatin1String(".png"));
if (!path.exists())
{
const QIcon icon = QIcon::fromTheme(iconId);
if (!icon.isNull())
icon.pixmap(32).save(path);
icon.pixmap(32).save(path.toString());
else
path = getIconPathFromResources(iconId);
}
@@ -292,17 +291,17 @@ QString UIThemeManager::getIconPath(const QString &iconId) const
return getIconPathFromResources(iconId, {});
}
QString UIThemeManager::getIconPathFromResources(const QString &iconId, const QString &fallback) const
Path UIThemeManager::getIconPathFromResources(const QString &iconId, const QString &fallback) const
{
if (m_useCustomTheme && m_themeSource)
{
const QString customIcon = m_themeSource->iconPath(iconId);
const Path customIcon = m_themeSource->iconPath(iconId);
if (!customIcon.isEmpty())
return customIcon;
if (!fallback.isEmpty())
{
const QString fallbackIcon = m_themeSource->iconPath(fallback);
const Path fallbackIcon = m_themeSource->iconPath(fallback);
if (!fallbackIcon.isEmpty())
return fallbackIcon;
}

View File

@@ -36,6 +36,8 @@
#include <QObject>
#include <QString>
#include "base/pathfwd.h"
class UIThemeSource
{
public:
@@ -43,7 +45,7 @@ public:
virtual QByteArray readStyleSheet() = 0;
virtual QByteArray readConfig() = 0;
virtual QString iconPath(const QString &iconId) const = 0;
virtual Path iconPath(const QString &iconId) const = 0;
};
class UIThemeManager : public QObject
@@ -56,7 +58,7 @@ public:
static void freeInstance();
static UIThemeManager *instance();
QString getIconPath(const QString &iconId) const;
Path getIconPath(const QString &iconId) const;
QIcon getIcon(const QString &iconId, const QString &fallback = {}) const;
QIcon getFlagIcon(const QString &countryIsoCode) const;
@@ -68,7 +70,7 @@ public:
private:
UIThemeManager(); // singleton class
QString getIconPathFromResources(const QString &iconId, const QString &fallback = {}) const;
Path getIconPathFromResources(const QString &iconId, const QString &fallback = {}) const;
void loadColorsFromJSONConfig();
void applyPalette() const;
void applyStyleSheet() const;

View File

@@ -48,6 +48,7 @@
#include <QWidget>
#include <QWindow>
#include "base/path.h"
#include "base/utils/fs.h"
#include "base/utils/version.h"
@@ -72,23 +73,23 @@ QPixmap Utils::Gui::scaledPixmap(const QIcon &icon, const QWidget *widget, const
return icon.pixmap(scaledHeight);
}
QPixmap Utils::Gui::scaledPixmap(const QString &path, const QWidget *widget, const int height)
QPixmap Utils::Gui::scaledPixmap(const Path &path, const QWidget *widget, const int height)
{
const QPixmap pixmap(path);
const QPixmap pixmap {path.data()};
const int scaledHeight = ((height > 0) ? height : pixmap.height()) * Utils::Gui::screenScalingFactor(widget);
return pixmap.scaledToHeight(scaledHeight, Qt::SmoothTransformation);
}
QPixmap Utils::Gui::scaledPixmapSvg(const QString &path, const QWidget *widget, const int baseHeight)
QPixmap Utils::Gui::scaledPixmapSvg(const Path &path, const QWidget *widget, const int baseHeight)
{
const int scaledHeight = baseHeight * Utils::Gui::screenScalingFactor(widget);
const QString normalizedKey = path + '@' + QString::number(scaledHeight);
const QString normalizedKey = path.data() + '@' + QString::number(scaledHeight);
QPixmap pm;
QPixmapCache cache;
if (!cache.find(normalizedKey, &pm))
{
pm = QIcon(path).pixmap(scaledHeight);
pm = QIcon(path.data()).pixmap(scaledHeight);
cache.insert(normalizedKey, pm);
}
return pm;
@@ -143,32 +144,29 @@ QPoint Utils::Gui::screenCenter(const QWidget *w)
}
// Open the given path with an appropriate application
void Utils::Gui::openPath(const QString &absolutePath)
void Utils::Gui::openPath(const Path &path)
{
const QString path = Utils::Fs::toUniformPath(absolutePath);
// Hack to access samba shares with QDesktopServices::openUrl
if (path.startsWith("//"))
QDesktopServices::openUrl(Utils::Fs::toNativePath("file:" + path));
if (path.data().startsWith("//"))
QDesktopServices::openUrl(QUrl(QString::fromLatin1("file:") + path.toString()));
else
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
QDesktopServices::openUrl(QUrl::fromLocalFile(path.data()));
}
// Open the parent directory of the given path with a file manager and select
// (if possible) the item at the given path
void Utils::Gui::openFolderSelect(const QString &absolutePath)
void Utils::Gui::openFolderSelect(const Path &path)
{
QString path {Utils::Fs::toUniformPath(absolutePath)};
const QFileInfo pathInfo {path};
// If the item to select doesn't exist, try to open its parent
if (!pathInfo.exists(path))
if (!path.exists())
{
openPath(path.left(path.lastIndexOf('/')));
openPath(path.parentPath());
return;
}
#ifdef Q_OS_WIN
HRESULT hresult = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
PIDLIST_ABSOLUTE pidl = ::ILCreateFromPathW(reinterpret_cast<PCTSTR>(Utils::Fs::toNativePath(path).utf16()));
PIDLIST_ABSOLUTE pidl = ::ILCreateFromPathW(reinterpret_cast<PCTSTR>(path.toString().utf16()));
if (pidl)
{
::SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0);
@@ -183,38 +181,34 @@ void Utils::Gui::openFolderSelect(const QString &absolutePath)
const QString output = proc.readLine().simplified();
if ((output == "dolphin.desktop") || (output == "org.kde.dolphin.desktop"))
{
proc.startDetached("dolphin", {"--select", Utils::Fs::toNativePath(path)});
proc.startDetached("dolphin", {"--select", path.toString()});
}
else if ((output == "nautilus.desktop") || (output == "org.gnome.Nautilus.desktop")
|| (output == "nautilus-folder-handler.desktop"))
{
if (pathInfo.isDir())
path = path.left(path.lastIndexOf('/'));
{
proc.start("nautilus", {"--version"});
proc.waitForFinished();
const QString nautilusVerStr = QString(proc.readLine()).remove(QRegularExpression("[^0-9.]"));
using NautilusVersion = Utils::Version<int, 3>;
if (NautilusVersion::tryParse(nautilusVerStr, {1, 0, 0}) > NautilusVersion {3, 28})
proc.startDetached("nautilus", {Utils::Fs::toNativePath(path)});
proc.startDetached("nautilus", {(Fs::isDir(path) ? path.parentPath() : path).toString()});
else
proc.startDetached("nautilus", {"--no-desktop", Utils::Fs::toNativePath(path)});
proc.startDetached("nautilus", {"--no-desktop", (Fs::isDir(path) ? path.parentPath() : path).toString()});
}
else if (output == "nemo.desktop")
{
if (pathInfo.isDir())
path = path.left(path.lastIndexOf('/'));
proc.startDetached("nemo", {"--no-desktop", Utils::Fs::toNativePath(path)});
proc.startDetached("nemo", {"--no-desktop", (Fs::isDir(path) ? path.parentPath() : path).toString()});
}
else if ((output == "konqueror.desktop") || (output == "kfmclient_dir.desktop"))
{
proc.startDetached("konqueror", {"--select", Utils::Fs::toNativePath(path)});
proc.startDetached("konqueror", {"--select", path.toString()});
}
else
{
// "caja" manager can't pinpoint the file, see: https://github.com/qbittorrent/qBittorrent/issues/5003
openPath(path.left(path.lastIndexOf('/')));
openPath(path.parentPath());
}
#else
openPath(path.left(path.lastIndexOf('/')));
openPath(path.parentPath());
#endif
}

View File

@@ -30,34 +30,33 @@
#include <QSize>
#include "base/pathfwd.h"
class QIcon;
class QPixmap;
class QPoint;
class QWidget;
namespace Utils
namespace Utils::Gui
{
namespace Gui
void resize(QWidget *widget, const QSize &newSize = {});
qreal screenScalingFactor(const QWidget *widget);
template <typename T>
T scaledSize(const QWidget *widget, const T &size)
{
void resize(QWidget *widget, const QSize &newSize = {});
qreal screenScalingFactor(const QWidget *widget);
template <typename T>
T scaledSize(const QWidget *widget, const T &size)
{
return (size * screenScalingFactor(widget));
}
QPixmap scaledPixmap(const QIcon &icon, const QWidget *widget, int height);
QPixmap scaledPixmap(const QString &path, const QWidget *widget, int height = 0);
QPixmap scaledPixmapSvg(const QString &path, const QWidget *widget, int baseHeight);
QSize smallIconSize(const QWidget *widget = nullptr);
QSize mediumIconSize(const QWidget *widget = nullptr);
QSize largeIconSize(const QWidget *widget = nullptr);
QPoint screenCenter(const QWidget *w);
void openPath(const QString &absolutePath);
void openFolderSelect(const QString &absolutePath);
return (size * screenScalingFactor(widget));
}
QPixmap scaledPixmap(const QIcon &icon, const QWidget *widget, int height);
QPixmap scaledPixmap(const Path &path, const QWidget *widget, int height = 0);
QPixmap scaledPixmapSvg(const Path &path, const QWidget *widget, int baseHeight);
QSize smallIconSize(const QWidget *widget = nullptr);
QSize mediumIconSize(const QWidget *widget = nullptr);
QSize largeIconSize(const QWidget *widget = nullptr);
QPoint screenCenter(const QWidget *w);
void openPath(const Path &path);
void openFolderSelect(const Path &path);
}

View File

@@ -138,13 +138,13 @@ void WatchedFolderOptionsDialog::onCategoryChanged(const int index)
const auto *btSession = BitTorrent::Session::instance();
const QString categoryName = m_ui->categoryComboBox->currentText();
const QString savePath = btSession->categorySavePath(categoryName);
m_ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath));
const Path savePath = btSession->categorySavePath(categoryName);
m_ui->savePath->setSelectedPath(savePath);
const QString finishedSavePath = btSession->categoryDownloadPath(categoryName);
m_ui->downloadPath->setSelectedPath(Utils::Fs::toNativePath(finishedSavePath));
const Path downloadPath = btSession->categoryDownloadPath(categoryName);
m_ui->downloadPath->setSelectedPath(downloadPath);
m_ui->groupBoxDownloadPath->setChecked(!finishedSavePath.isEmpty());
m_ui->groupBoxDownloadPath->setChecked(!downloadPath.isEmpty());
}
}
@@ -152,11 +152,11 @@ void WatchedFolderOptionsDialog::populateSavePaths()
{
const auto *btSession = BitTorrent::Session::instance();
const QString defaultSavePath {btSession->savePath()};
const Path defaultSavePath {btSession->savePath()};
m_ui->savePath->setSelectedPath(!m_savePath.isEmpty() ? m_savePath : defaultSavePath);
const QString defaultFinishedSavePath {btSession->downloadPath()};
m_ui->downloadPath->setSelectedPath(!m_downloadPath.isEmpty() ? m_downloadPath : defaultFinishedSavePath);
const Path defaultDownloadPath {btSession->downloadPath()};
m_ui->downloadPath->setSelectedPath(!m_downloadPath.isEmpty() ? m_downloadPath : defaultDownloadPath);
m_ui->groupBoxDownloadPath->setChecked(m_useDownloadPath);
}
@@ -178,15 +178,15 @@ void WatchedFolderOptionsDialog::onTMMChanged(const int index)
m_ui->savePath->blockSignals(true);
m_savePath = m_ui->savePath->selectedPath();
const QString savePath = btSession->categorySavePath(m_ui->categoryComboBox->currentText());
const Path savePath = btSession->categorySavePath(m_ui->categoryComboBox->currentText());
m_ui->savePath->setSelectedPath(savePath);
m_ui->downloadPath->blockSignals(true);
m_downloadPath = m_ui->downloadPath->selectedPath();
const QString finishedSavePath = btSession->categoryDownloadPath(m_ui->categoryComboBox->currentText());
m_ui->downloadPath->setSelectedPath(finishedSavePath);
const Path downloadPath = btSession->categoryDownloadPath(m_ui->categoryComboBox->currentText());
m_ui->downloadPath->setSelectedPath(downloadPath);
m_useDownloadPath = m_ui->groupBoxDownloadPath->isChecked();
m_ui->groupBoxDownloadPath->setChecked(!finishedSavePath.isEmpty());
m_ui->groupBoxDownloadPath->setChecked(!downloadPath.isEmpty());
}
}

View File

@@ -30,6 +30,7 @@
#include <QDialog>
#include "base/path.h"
#include "base/settingvalue.h"
#include "base/torrentfileswatcher.h"
@@ -57,8 +58,8 @@ private:
void onCategoryChanged(int index);
Ui::WatchedFolderOptionsDialog *m_ui;
QString m_savePath;
QString m_downloadPath;
Path m_savePath;
Path m_downloadPath;
bool m_useDownloadPath = false;
SettingValue<QSize> m_storeDialogSize;
};

View File

@@ -61,7 +61,7 @@ QVariant WatchedFoldersModel::data(const QModelIndex &index, const int role) con
return {};
if (role == Qt::DisplayRole)
return Utils::Fs::toNativePath(m_watchedFolders.at(index.row()));
return m_watchedFolders.at(index.row()).toString();
return {};
}
@@ -91,7 +91,7 @@ bool WatchedFoldersModel::removeRows(const int row, const int count, const QMode
beginRemoveRows(parent, firstRow, lastRow);
for (int i = firstRow; i <= lastRow; ++i)
{
const QString folderPath = m_watchedFolders.takeAt(i);
const Path folderPath = m_watchedFolders.takeAt(i);
m_watchedFoldersOptions.remove(folderPath);
m_deletedFolders.insert(folderPath);
}
@@ -100,23 +100,28 @@ bool WatchedFoldersModel::removeRows(const int row, const int count, const QMode
return true;
}
void WatchedFoldersModel::addFolder(const QString &path, const TorrentFilesWatcher::WatchedFolderOptions &options)
void WatchedFoldersModel::addFolder(const Path &path, const TorrentFilesWatcher::WatchedFolderOptions &options)
{
const QString cleanWatchPath = m_fsWatcher->makeCleanPath(path);
if (m_watchedFoldersOptions.contains(cleanWatchPath))
throw RuntimeError(tr("Folder '%1' is already in watch list.").arg(path));
if (path.isEmpty())
throw InvalidArgument(tr("Watched folder path cannot be empty."));
const QDir watchDir {cleanWatchPath};
if (path.isRelative())
throw InvalidArgument(tr("Watched folder path cannot be relative."));
if (m_watchedFoldersOptions.contains(path))
throw RuntimeError(tr("Folder '%1' is already in watch list.").arg(path.toString()));
const QDir watchDir {path.data()};
if (!watchDir.exists())
throw RuntimeError(tr("Folder '%1' doesn't exist.").arg(path));
throw RuntimeError(tr("Folder '%1' doesn't exist.").arg(path.toString()));
if (!watchDir.isReadable())
throw RuntimeError(tr("Folder '%1' isn't readable.").arg(path));
throw RuntimeError(tr("Folder '%1' isn't readable.").arg(path.toString()));
m_deletedFolders.remove(cleanWatchPath);
m_deletedFolders.remove(path);
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_watchedFolders.append(cleanWatchPath);
m_watchedFoldersOptions[cleanWatchPath] = options;
m_watchedFolders.append(path);
m_watchedFoldersOptions[path] = options;
endInsertRows();
}
@@ -124,7 +129,7 @@ TorrentFilesWatcher::WatchedFolderOptions WatchedFoldersModel::folderOptions(con
{
Q_ASSERT((row >= 0) && (row < rowCount()));
const QString folderPath = m_watchedFolders.at(row);
const Path folderPath = m_watchedFolders.at(row);
return m_watchedFoldersOptions[folderPath];
}
@@ -132,24 +137,24 @@ void WatchedFoldersModel::setFolderOptions(const int row, const TorrentFilesWatc
{
Q_ASSERT((row >= 0) && (row < rowCount()));
const QString folderPath = m_watchedFolders.at(row);
const Path folderPath = m_watchedFolders.at(row);
m_watchedFoldersOptions[folderPath] = options;
}
void WatchedFoldersModel::apply()
{
const QSet<QString> deletedFolders {m_deletedFolders};
const QSet<Path> deletedFolders {m_deletedFolders};
// We have to clear `m_deletedFolders` for optimization reason, otherwise
// it will be cleared one element at a time in `onFolderRemoved()` handler
m_deletedFolders.clear();
for (const QString &path : deletedFolders)
for (const Path &path : deletedFolders)
m_fsWatcher->removeWatchedFolder(path);
for (const QString &path : asConst(m_watchedFolders))
for (const Path &path : asConst(m_watchedFolders))
m_fsWatcher->setWatchedFolder(path, m_watchedFoldersOptions.value(path));
}
void WatchedFoldersModel::onFolderSet(const QString &path, const TorrentFilesWatcher::WatchedFolderOptions &options)
void WatchedFoldersModel::onFolderSet(const Path &path, const TorrentFilesWatcher::WatchedFolderOptions &options)
{
if (!m_watchedFoldersOptions.contains(path))
{
@@ -166,7 +171,7 @@ void WatchedFoldersModel::onFolderSet(const QString &path, const TorrentFilesWat
}
}
void WatchedFoldersModel::onFolderRemoved(const QString &path)
void WatchedFoldersModel::onFolderRemoved(const Path &path)
{
const int row = m_watchedFolders.indexOf(path);
if (row >= 0)

View File

@@ -34,6 +34,7 @@
#include <QSet>
#include <QStringList>
#include "base/path.h"
#include "base/torrentfileswatcher.h"
class WatchedFoldersModel final : public QAbstractListModel
@@ -50,7 +51,7 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
void addFolder(const QString &path, const TorrentFilesWatcher::WatchedFolderOptions &options);
void addFolder(const Path &path, const TorrentFilesWatcher::WatchedFolderOptions &options);
TorrentFilesWatcher::WatchedFolderOptions folderOptions(int row) const;
void setFolderOptions(int row, const TorrentFilesWatcher::WatchedFolderOptions &options);
@@ -58,11 +59,11 @@ public:
void apply();
private:
void onFolderSet(const QString &path, const TorrentFilesWatcher::WatchedFolderOptions &options);
void onFolderRemoved(const QString &path);
void onFolderSet(const Path &path, const TorrentFilesWatcher::WatchedFolderOptions &options);
void onFolderRemoved(const Path &path);
TorrentFilesWatcher *m_fsWatcher;
QStringList m_watchedFolders;
QHash<QString, TorrentFilesWatcher::WatchedFolderOptions> m_watchedFoldersOptions;
QSet<QString> m_deletedFolders;
PathList m_watchedFolders;
QHash<Path, TorrentFilesWatcher::WatchedFolderOptions> m_watchedFoldersOptions;
QSet<Path> m_deletedFolders;
};