diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 7a444a8e5..818f3f975 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -40,6 +40,8 @@ cookiesmodel.h deletionconfirmationdlg.h downloadfromurldlg.h executionlog.h +fspathedit.h +fspathedit_p.h guiiconprovider.h hidabletabwidget.h ico.h @@ -80,6 +82,8 @@ categoryfilterwidget.cpp cookiesdialog.cpp cookiesmodel.cpp executionlog.cpp +fspathedit.cpp +fspathedit_p.cpp guiiconprovider.cpp ico.cpp loglistwidget.cpp diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index bbdb6901c..56ba3f8ff 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "base/preferences.h" #include "base/settingsstorage.h" @@ -90,6 +91,9 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP ui->lblMetaLoading->setVisible(false); ui->progMetaLoading->setVisible(false); + ui->savePath->setMode(FileSystemPathEdit::Mode::DirectorySave); + ui->savePath->setDialogCaption(tr("Choose save path")); + auto session = BitTorrent::Session::instance(); if (m_torrentParams.addPaused == TriStateBool::True) @@ -103,8 +107,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP ui->comboTTM->setCurrentIndex(!session->isAutoTMMDisabledByDefault()); ui->comboTTM->blockSignals(false); populateSavePathComboBox(); - connect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onSavePathChanged(int))); - connect(ui->browseButton, SIGNAL(clicked()), SLOT(browseButton_clicked())); + connect(ui->savePath, &FileSystemPathEdit::selectedPathChanged, this, &AddNewTorrentDialog::onSavePathChanged); ui->defaultSavePathCheckBox->setVisible(false); // Default path is selected by default if (m_torrentParams.createSubfolder == TriStateBool::True) @@ -353,7 +356,7 @@ void AddNewTorrentDialog::showAdvancedSettings(bool show) void AddNewTorrentDialog::saveSavePathHistory() const { - QDir selectedSavePath(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString()); + QDir selectedSavePath(ui->savePath->selectedPath()); // Get current history QStringList history = settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList(); QList historyDirs; @@ -374,8 +377,8 @@ void AddNewTorrentDialog::saveSavePathHistory() const int AddNewTorrentDialog::indexOfSavePath(const QString &save_path) { QDir saveDir(save_path); - for (int i = 0; i < ui->savePathComboBox->count(); ++i) - if (QDir(ui->savePathComboBox->itemData(i).toString()) == saveDir) + for (int i = 0; i < ui->savePath->count(); ++i) + if (QDir(ui->savePath->item(i)) == saveDir) return i; return -1; } @@ -401,23 +404,18 @@ void AddNewTorrentDialog::updateDiskSpaceLabel() QString size_string = torrent_size ? Utils::Misc::friendlyUnit(torrent_size) : QString(tr("Not Available", "This size is unavailable.")); size_string += " ("; size_string += tr("Free space on disk: %1").arg(Utils::Misc::friendlyUnit(Utils::Fs::freeDiskSpaceOnPath( - ui->savePathComboBox->itemData( - ui->savePathComboBox->currentIndex()).toString()))); + ui->savePath->selectedPath()))); size_string += ")"; ui->size_lbl->setText(size_string); } -void AddNewTorrentDialog::onSavePathChanged(int index) +void AddNewTorrentDialog::onSavePathChanged(const QString &newPath) { // Toggle default save path setting checkbox visibility ui->defaultSavePathCheckBox->setChecked(false); - ui->defaultSavePathCheckBox->setVisible( - QDir(ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString()) - != QDir(BitTorrent::Session::instance()->defaultSavePath())); - + ui->defaultSavePathCheckBox->setVisible(QDir(newPath) != QDir(BitTorrent::Session::instance()->defaultSavePath())); // Remember index - m_oldIndex = index; - + m_oldIndex = ui->savePath->currentIndex(); updateDiskSpaceLabel(); } @@ -427,8 +425,7 @@ void AddNewTorrentDialog::categoryChanged(int index) if (ui->comboTTM->currentIndex() == 1) { QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText()); - ui->savePathComboBox->setItemText(0, Utils::Fs::toNativePath(savePath)); - ui->savePathComboBox->setItemData(0, savePath); + ui->savePath->setSelectedPath(Utils::Fs::toNativePath(savePath)); } } @@ -437,35 +434,11 @@ void AddNewTorrentDialog::setSavePath(const QString &newPath) int existingIndex = indexOfSavePath(newPath); if (existingIndex < 0) { // New path, prepend to combo box - ui->savePathComboBox->insertItem(0, Utils::Fs::toNativePath(newPath), newPath); + ui->savePath->insertItem(0, newPath); existingIndex = 0; } - ui->savePathComboBox->setCurrentIndex(existingIndex); - onSavePathChanged(existingIndex); -} - -void AddNewTorrentDialog::browseButton_clicked() -{ - disconnect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onSavePathChanged(int))); - - // User is asking for a new save path - QString curSavePath = ui->savePathComboBox->itemText(m_oldIndex); - QString newPath; - - if (!curSavePath.isEmpty() && QDir(curSavePath).exists()) - newPath = QFileDialog::getExistingDirectory(this, tr("Choose save path"), curSavePath); - else - newPath = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath()); - - if (!newPath.isEmpty()) { - setSavePath(newPath); - } - else { - // Restore index - ui->savePathComboBox->setCurrentIndex(m_oldIndex); - } - - connect(ui->savePathComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onSavePathChanged(int))); + ui->savePath->setCurrentIndex(existingIndex); + onSavePathChanged(newPath); } void AddNewTorrentDialog::renameSelectedFile() @@ -573,14 +546,14 @@ void AddNewTorrentDialog::populateSavePathComboBox() { QString defSavePath = BitTorrent::Session::instance()->defaultSavePath(); - ui->savePathComboBox->clear(); - ui->savePathComboBox->addItem(Utils::Fs::toNativePath(defSavePath), defSavePath); + ui->savePath->clear(); + ui->savePath->addItem(defSavePath); QDir defaultSaveDir(defSavePath); // Load save path history foreach (const QString &savePath, settings()->loadValue(KEY_SAVEPATHHISTORY).toStringList()) if (QDir(savePath) != defaultSaveDir) - ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath); - + ui->savePath->addItem(savePath); + if (!m_torrentParams.savePath.isEmpty()) setSavePath(m_torrentParams.savePath); } @@ -646,7 +619,7 @@ void AddNewTorrentDialog::accept() m_torrentParams.addPaused = TriStateBool(!ui->startTorrentCheckBox->isChecked()); m_torrentParams.createSubfolder = TriStateBool(ui->createSubfolderCheckBox->isChecked()); - QString savePath = ui->savePathComboBox->itemData(ui->savePathComboBox->currentIndex()).toString(); + QString savePath = ui->savePath->selectedPath(); if (ui->comboTTM->currentIndex() != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode. m_torrentParams.savePath = savePath; saveSavePathHistory(); @@ -776,16 +749,16 @@ void AddNewTorrentDialog::TMMChanged(int index) if (index != 1) { // 0 is Manual mode and 1 is Automatic mode. Handle all non 1 values as manual mode. populateSavePathComboBox(); ui->groupBoxSavePath->setEnabled(true); - ui->savePathComboBox->blockSignals(false); - ui->savePathComboBox->setCurrentIndex(m_oldIndex < ui->savePathComboBox->count() ? m_oldIndex : ui->savePathComboBox->count() - 1); + ui->savePath->blockSignals(false); + ui->savePath->setCurrentIndex(m_oldIndex < ui->savePath->count() ? m_oldIndex : ui->savePath->count() - 1); ui->adv_button->setEnabled(true); } else { ui->groupBoxSavePath->setEnabled(false); - ui->savePathComboBox->blockSignals(true); - ui->savePathComboBox->clear(); + ui->savePath->blockSignals(true); + ui->savePath->clear(); QString savePath = BitTorrent::Session::instance()->categorySavePath(ui->categoryComboBox->currentText()); - ui->savePathComboBox->addItem(Utils::Fs::toNativePath(savePath), savePath); + ui->savePath->addItem(savePath); ui->defaultSavePathCheckBox->setVisible(false); ui->adv_button->setChecked(true); ui->adv_button->setEnabled(false); diff --git a/src/gui/addnewtorrentdialog.h b/src/gui/addnewtorrentdialog.h index ad28474d8..90043d925 100644 --- a/src/gui/addnewtorrentdialog.h +++ b/src/gui/addnewtorrentdialog.h @@ -73,10 +73,9 @@ private slots: void showAdvancedSettings(bool show); void displayContentTreeMenu(const QPoint&); void updateDiskSpaceLabel(); - void onSavePathChanged(int); + void onSavePathChanged(const QString &newPath); void renameSelectedFile(); void updateMetadata(const BitTorrent::TorrentInfo &info); - void browseButton_clicked(); void handleDownloadFailed(const QString &url, const QString &reason); void handleRedirectedToMagnet(const QString &url, const QString &magnetUri); void handleDownloadFinished(const QString &url, const QString &filePath); diff --git a/src/gui/addnewtorrentdialog.ui b/src/gui/addnewtorrentdialog.ui index a4cfca76a..9f8747101 100644 --- a/src/gui/addnewtorrentdialog.ui +++ b/src/gui/addnewtorrentdialog.ui @@ -7,7 +7,7 @@ 0 0 414 - 661 + 630 @@ -59,28 +59,7 @@ - - - - - - 0 - 0 - - - - QComboBox::AdjustToMinimumContentsLength - - - - - - - Browse... - - - - + @@ -405,10 +384,15 @@ QTreeView
torrentcontenttreeview.h
+ + FileSystemPathComboEdit + QWidget +
fspathedit.h
+ 1 +
- savePathComboBox - browseButton + savePath defaultSavePathCheckBox never_show_cb adv_button diff --git a/src/gui/fspathedit.cpp b/src/gui/fspathedit.cpp new file mode 100644 index 000000000..d5a3eda36 --- /dev/null +++ b/src/gui/fspathedit.cpp @@ -0,0 +1,363 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2016 Eugene Shalygin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include "fspathedit.h" + +#include +#include +#include +#include +#include +#include + +#include "base/utils/fs.h" +#include "fspathedit_p.h" + +namespace +{ + struct TrStringWithComment + { + const char *source; + const char *comment; + + QString tr() const + { + return QObject::tr(source, comment); + } + }; + + constexpr TrStringWithComment browseButtonBriefText = + QT_TRANSLATE_NOOP3("FileSystemPathEdit", "...", "Launch file dialog button text (brief)"); + constexpr TrStringWithComment browseButtonFullText = + QT_TRANSLATE_NOOP3("FileSystemPathEdit", "&Browse...", "Launch file dialog button text (full)"); + constexpr TrStringWithComment defaultDialogCaptionForFile = + QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a file", "Caption for file open/save dialog"); + constexpr TrStringWithComment defaultDialogCaptionForDirectory = + QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a folder", "Caption for directory open dialog"); +} + +class FileSystemPathEdit::FileSystemPathEditPrivate +{ + Q_DECLARE_PUBLIC(FileSystemPathEdit) + Q_DISABLE_COPY(FileSystemPathEditPrivate) + + FileSystemPathEditPrivate(FileSystemPathEdit *q, Private::FileEditorWithCompletion *editor); + + void modeChanged(); + void browseActionTriggered(); + QString dialogCaptionOrDefault() const; + + FileSystemPathEdit *q_ptr; + QScopedPointer m_editor; + QAction *m_browseAction; + QToolButton *m_browseBtn; + QString m_fileNameFilter; + Mode m_mode; + QString m_lastSignaledPath; + QString m_dialogCaption; +}; + +FileSystemPathEdit::FileSystemPathEditPrivate::FileSystemPathEditPrivate( + FileSystemPathEdit *q, Private::FileEditorWithCompletion *editor) + : q_ptr {q} + , m_editor {editor} + , m_browseAction {new QAction(q)} + , m_browseBtn {new QToolButton(q)} + , m_mode {FileSystemPathEdit::Mode::FileOpen} +{ + m_browseAction->setIconText(browseButtonBriefText.tr()); + m_browseAction->setText(browseButtonFullText.tr()); + m_browseAction->setToolTip(browseButtonFullText.tr().remove(QLatin1Char('&'))); + m_browseAction->setShortcut(Qt::CTRL + Qt::Key_B); + m_browseBtn->setDefaultAction(m_browseAction); + m_fileNameFilter = tr("Any file") + QLatin1String(" (*)"); + m_editor->setBrowseAction(m_browseAction); + modeChanged(); +} + +void FileSystemPathEdit::FileSystemPathEditPrivate::browseActionTriggered() +{ + Q_Q(FileSystemPathEdit); + QString filter = q->fileNameFilter(); + QString directory = q->currentDirectory().isEmpty() ? QDir::homePath() : q->currentDirectory(); + + QString selectedPath; + switch (m_mode) { + case FileSystemPathEdit::Mode::FileOpen: + selectedPath = QFileDialog::getOpenFileName(q, dialogCaptionOrDefault(), directory, filter); + break; + case FileSystemPathEdit::Mode::FileSave: + selectedPath = QFileDialog::getSaveFileName(q, dialogCaptionOrDefault(), directory, filter, &filter); + break; + case FileSystemPathEdit::Mode::DirectoryOpen: + case FileSystemPathEdit::Mode::DirectorySave: + selectedPath = QFileDialog::getExistingDirectory(q, dialogCaptionOrDefault(), + directory, QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly); + break; + default: + throw std::logic_error("Unknown FileSystemPathEdit mode"); + } + if (!selectedPath.isEmpty()) + q->setEditWidgetText(selectedPath); +} + +QString FileSystemPathEdit::FileSystemPathEditPrivate::dialogCaptionOrDefault() const +{ + if (!m_dialogCaption.isEmpty()) + return m_dialogCaption; + + switch (m_mode) { + case FileSystemPathEdit::Mode::FileOpen: + case FileSystemPathEdit::Mode::FileSave: + return defaultDialogCaptionForFile.tr(); + case FileSystemPathEdit::Mode::DirectoryOpen: + case FileSystemPathEdit::Mode::DirectorySave: + return defaultDialogCaptionForDirectory.tr(); + default: + throw std::logic_error("Unknown FileSystemPathEdit mode"); + } +} + +void FileSystemPathEdit::FileSystemPathEditPrivate::modeChanged() +{ + QStyle::StandardPixmap pixmap = QStyle::SP_DialogOpenButton; + bool showDirsOnly = false; + switch (m_mode) { + case FileSystemPathEdit::Mode::FileOpen: + case FileSystemPathEdit::Mode::FileSave: + pixmap = QStyle::SP_DialogOpenButton; + showDirsOnly = false; + break; + case FileSystemPathEdit::Mode::DirectoryOpen: + case FileSystemPathEdit::Mode::DirectorySave: + pixmap = QStyle::SP_DirOpenIcon; + showDirsOnly = true; + break; + default: + throw std::logic_error("Unknown FileSystemPathEdit mode"); + } + m_browseAction->setIcon(QApplication::style()->standardIcon(pixmap)); + m_editor->completeDirectoriesOnly(showDirsOnly); +} + +FileSystemPathEdit::FileSystemPathEdit(Private::FileEditorWithCompletion *editor, QWidget *parent) + : QWidget(parent) + , d_ptr(new FileSystemPathEditPrivate(this, editor)) +{ + Q_D(FileSystemPathEdit); + editor->widget()->setParent(this); + + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(editor->widget()); + layout->addWidget(d->m_browseBtn); + + connect(d->m_browseAction, &QAction::triggered, [this]() {this->d_func()->browseActionTriggered();}); +} + +FileSystemPathEdit::~FileSystemPathEdit() = default; + +QString FileSystemPathEdit::selectedPath() const +{ + return Utils::Fs::fromNativePath(editWidgetText()); +} + +void FileSystemPathEdit::setSelectedPath(const QString &val) +{ + Q_D(FileSystemPathEdit); + setEditWidgetText(Utils::Fs::toNativePath(val)); + d->m_editor->widget()->setToolTip(val); +} + +QString FileSystemPathEdit::fileNameFilter() const +{ + Q_D(const FileSystemPathEdit); + return d->m_fileNameFilter; +} + +void FileSystemPathEdit::setFileNameFilter(const QString &val) +{ + Q_D(FileSystemPathEdit); + d->m_fileNameFilter = val; + +#if 0 + // QFileSystemModel applies name filters to directories too. + // To use the filters we have to subclass QFileSystemModel and skip directories while filtering + // extract file masks + const int openBracePos = val.indexOf(QLatin1Char('('), 0); + const int closeBracePos = val.indexOf(QLatin1Char(')'), openBracePos + 1); + if ((openBracePos > 0) && (closeBracePos > 0) && (closeBracePos > openBracePos + 2)) { + QString filterString = val.mid(openBracePos + 1, closeBracePos - openBracePos - 1); + if (filterString == QLatin1String("*")) { // no filters + d->m_editor->setFilenameFilters({}); + } + else { + QStringList filters = filterString.split(QLatin1Char(' '), QString::SkipEmptyParts); + d->m_editor->setFilenameFilters(filters); + } + } + else { + d->m_editor->setFilenameFilters({}); + } +#endif +} + +bool FileSystemPathEdit::briefBrowseButtonCaption() const +{ + Q_D(const FileSystemPathEdit); + return d->m_browseBtn->text() == browseButtonBriefText.tr(); +} + +void FileSystemPathEdit::setBriefBrowseButtonCaption(bool brief) +{ + Q_D(FileSystemPathEdit); + d->m_browseBtn->setText(brief ? browseButtonBriefText.tr() : browseButtonFullText.tr()); +} + +void FileSystemPathEdit::onPathEdited() +{ + Q_D(FileSystemPathEdit); + QString newPath = selectedPath(); + if (newPath != d->m_lastSignaledPath) { + emit selectedPathChanged(newPath); + d->m_lastSignaledPath = newPath; + d->m_editor->widget()->setToolTip(editWidgetText()); + } +} + +FileSystemPathEdit::Mode FileSystemPathEdit::mode() const +{ + Q_D(const FileSystemPathEdit); + return d->m_mode; +} + +void FileSystemPathEdit::setMode(FileSystemPathEdit::Mode theMode) +{ + Q_D(FileSystemPathEdit); + d->m_mode = theMode; + d->modeChanged(); +} + +QString FileSystemPathEdit::dialogCaption() const +{ + Q_D(const FileSystemPathEdit); + return d->m_dialogCaption; +} + +void FileSystemPathEdit::setDialogCaption(const QString &caption) +{ + Q_D(FileSystemPathEdit); + d->m_dialogCaption = caption; +} + +QString FileSystemPathEdit::currentDirectory() const +{ + return QFileInfo(selectedPath()).absoluteDir().absolutePath(); +} + +QWidget *FileSystemPathEdit::editWidgetImpl() const +{ + Q_D(const FileSystemPathEdit); + return d->m_editor->widget(); +} + +// ------------------------- FileSystemPathLineEdit ---------------------- +FileSystemPathLineEdit::FileSystemPathLineEdit(QWidget *parent) + : FileSystemPathEdit(new WidgetType(), parent) +{ + connect(editWidget(), &QLineEdit::editingFinished, this, &FileSystemPathLineEdit::onPathEdited); + connect(editWidget(), &QLineEdit::textChanged, this, &FileSystemPathLineEdit::onPathEdited); +} + +QString FileSystemPathLineEdit::editWidgetText() const +{ + return editWidget()->text(); +} + +void FileSystemPathLineEdit::clear() +{ + editWidget()->clear(); +} + +void FileSystemPathLineEdit::setEditWidgetText(const QString &text) +{ + editWidget()->setText(text); +} + +// ----------------------- FileSystemPathComboEdit ----------------------- +FileSystemPathComboEdit::FileSystemPathComboEdit(QWidget *parent) + : FileSystemPathEdit(new WidgetType(), parent) +{ + editWidget()->setEditable(true); + connect(editWidget(), &QComboBox::currentTextChanged, this, &FileSystemPathComboEdit::onPathEdited); + connect(editWidget()->lineEdit(), &QLineEdit::editingFinished, this, &FileSystemPathComboEdit::onPathEdited); +} + +void FileSystemPathComboEdit::clear() +{ + editWidget()->clear(); +} + +int FileSystemPathComboEdit::count() const +{ + return editWidget()->count(); +} + +QString FileSystemPathComboEdit::item(int index) const +{ + return Utils::Fs::fromNativePath(editWidget()->itemText(index)); +} + +void FileSystemPathComboEdit::addItem(const QString &text) +{ + editWidget()->addItem(Utils::Fs::toNativePath(text)); +} + +void FileSystemPathComboEdit::insertItem(int index, const QString& text) +{ + editWidget()->insertItem(index, Utils::Fs::toNativePath(text)); +} + +int FileSystemPathComboEdit::currentIndex() const +{ + return editWidget()->currentIndex(); +} + +void FileSystemPathComboEdit::setCurrentIndex(int index) +{ + editWidget()->setCurrentIndex(index); +} + +QString FileSystemPathComboEdit::editWidgetText() const +{ + return editWidget()->currentText(); +} + +void FileSystemPathComboEdit::setEditWidgetText(const QString &text) +{ + editWidget()->setCurrentText(text); +} diff --git a/src/gui/fspathedit.h b/src/gui/fspathedit.h new file mode 100644 index 000000000..e7bf496ab --- /dev/null +++ b/src/gui/fspathedit.h @@ -0,0 +1,151 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2016 Eugene Shalygin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#ifndef QBT_FSPATHEDIT_H +#define QBT_FSPATHEDIT_H + +#include +#include + +namespace Private +{ + class FileEditorWithCompletion; + class FileLineEdit; + class FileComboEdit; +} + +/*! + * \brief + * Widget for editing strings which are paths in filesystem + */ +class FileSystemPathEdit: public QWidget +{ + Q_OBJECT + Q_ENUMS(Mode) + Q_PROPERTY(Mode mode READ mode WRITE setMode) + Q_PROPERTY(QString selectedPath READ selectedPath WRITE setSelectedPath NOTIFY selectedPathChanged) + Q_PROPERTY(QString fileNameFilter READ fileNameFilter WRITE setFileNameFilter) + Q_PROPERTY(QString dialogCaption READ dialogCaption WRITE setDialogCaption) + +public: + ~FileSystemPathEdit() override; + + enum class Mode + { + FileOpen, //!< opening files, shows open file dialog + FileSave, //!< saving files, shows save file dialog + DirectoryOpen, //!< selecting existing directories + DirectorySave //!< selecting directories for saving + }; + + Mode mode() const; + void setMode(Mode mode); + + QString currentDirectory() const; + QString selectedPath() const; + void setSelectedPath(const QString &val); + + QString fileNameFilter() const; + void setFileNameFilter(const QString &val); + + /// The browse button caption is "..." if true, and "Browse" otherwise + bool briefBrowseButtonCaption() const; + void setBriefBrowseButtonCaption(bool brief); + + QString dialogCaption() const; + void setDialogCaption(const QString &caption); + + virtual void clear() = 0; + +signals: + void selectedPathChanged(const QString &path); + +protected: + explicit FileSystemPathEdit(Private::FileEditorWithCompletion *editor, QWidget *parent); + + template + Widget *editWidget() const + { + return static_cast(editWidgetImpl()); + } + +protected slots: + void onPathEdited(); + +private: + virtual QString editWidgetText() const = 0; + virtual void setEditWidgetText(const QString &text) = 0; + + QWidget *editWidgetImpl() const; + Q_DISABLE_COPY(FileSystemPathEdit) + class FileSystemPathEditPrivate; + Q_DECLARE_PRIVATE(FileSystemPathEdit) + QScopedPointer const d_ptr; +}; + +/// Widget which uses QLineEdit for path editing +class FileSystemPathLineEdit: public FileSystemPathEdit +{ + using base = FileSystemPathEdit; + using WidgetType = Private::FileLineEdit; + +public: + explicit FileSystemPathLineEdit(QWidget *parent = nullptr); + + void clear() override; + +private: + QString editWidgetText() const override; + void setEditWidgetText(const QString &text) override; +}; + +/// Widget which uses QComboBox for path editing +class FileSystemPathComboEdit: public FileSystemPathEdit +{ + using base = FileSystemPathEdit; + using WidgetType = Private::FileComboEdit; + +public: + explicit FileSystemPathComboEdit(QWidget *parent = nullptr); + + void clear() override; + + int count() const; + QString item(int index) const; + void addItem(const QString &text); + void insertItem(int index, const QString &text); + + int currentIndex() const; + void setCurrentIndex(int index); + +private: + QString editWidgetText() const override; + void setEditWidgetText(const QString &text) override; +}; + +#endif // QBT_FSPATHEDIT_H diff --git a/src/gui/fspathedit_p.cpp b/src/gui/fspathedit_p.cpp new file mode 100644 index 000000000..8be1a87b7 --- /dev/null +++ b/src/gui/fspathedit_p.cpp @@ -0,0 +1,133 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2016 Eugene Shalygin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include "fspathedit_p.h" + +#include +#include + +Private::FileLineEdit::FileLineEdit(QWidget *parent) + : QLineEdit {parent} + , m_completerModel {new QFileSystemModel(this)} + , m_completer {new QCompleter(this)} + , m_browseAction {nullptr} +{ + m_completerModel->setRootPath(""); + m_completerModel->setIconProvider(&m_iconProvider); + m_completer->setModel(m_completerModel); + m_completer->setCompletionMode(QCompleter::PopupCompletion); + setCompleter(m_completer); + + connect(m_completerModel, &QFileSystemModel::directoryLoaded, this, &FileLineEdit::showCompletionPopup); +} + +Private::FileLineEdit::~FileLineEdit() +{ + delete m_completerModel; // has to be deleted before deleting the m_iconProvider object +} + +void Private::FileLineEdit::completeDirectoriesOnly(bool completeDirsOnly) +{ + QDir::Filters filters = completeDirsOnly ? QDir::Dirs : QDir::AllEntries; + filters |= QDir::NoDotAndDotDot; + m_completerModel->setFilter(filters); +} + +void Private::FileLineEdit::setFilenameFilters(const QStringList &filters) +{ + m_completerModel->setNameFilters(filters); +} + +void Private::FileLineEdit::setBrowseAction(QAction *action) +{ + m_browseAction = action; +} + +QWidget *Private::FileLineEdit::widget() +{ + return this; +} + +void Private::FileLineEdit::keyPressEvent(QKeyEvent *e) +{ + QLineEdit::keyPressEvent(e); + if ((e->key() == Qt::Key_Space) && (e->modifiers() == Qt::CTRL)) { + m_completerModel->setRootPath(QFileInfo(text()).absoluteDir().absolutePath()); + showCompletionPopup(); + } +} + +void Private::FileLineEdit::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu *menu = createStandardContextMenu(); + menu->addSeparator(); + if (m_browseAction) { + menu->addSeparator(); + menu->addAction(m_browseAction); + } + menu->exec(event->globalPos()); + delete menu; +} + +void Private::FileLineEdit::showCompletionPopup() +{ + m_completer->setCompletionPrefix(text()); + m_completer->complete(); +} + +Private::FileComboEdit::FileComboEdit(QWidget *parent) + : QComboBox {parent} +{ + setEditable(true); + setLineEdit(new FileLineEdit(this)); +} + +void Private::FileComboEdit::completeDirectoriesOnly(bool completeDirsOnly) +{ + static_cast(lineEdit())->completeDirectoriesOnly(completeDirsOnly); +} + +void Private::FileComboEdit::setBrowseAction(QAction *action) +{ + static_cast(lineEdit())->setBrowseAction(action); +} + +void Private::FileComboEdit::setFilenameFilters(const QStringList &filters) +{ + static_cast(lineEdit())->setFilenameFilters(filters); +} + +QWidget *Private::FileComboEdit::widget() +{ + return this; +} + +QString Private::FileComboEdit::text() const +{ + return currentText(); +} diff --git a/src/gui/fspathedit_p.h b/src/gui/fspathedit_p.h new file mode 100644 index 000000000..450a3ea52 --- /dev/null +++ b/src/gui/fspathedit_p.h @@ -0,0 +1,101 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2016 Eugene Shalygin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#ifndef QBT_GUI_FSPATHEDIT_P_H +#define QBT_GUI_FSPATHEDIT_P_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Private +{ + class FileEditorWithCompletion + { + public: + virtual ~FileEditorWithCompletion() = default; + virtual void completeDirectoriesOnly(bool completeDirsOnly) = 0; + virtual void setFilenameFilters(const QStringList &filters) = 0; + virtual void setBrowseAction(QAction *action) = 0; + virtual QWidget *widget() = 0; + }; + + class FileLineEdit: public QLineEdit, public FileEditorWithCompletion + { + Q_OBJECT + Q_DISABLE_COPY(FileLineEdit) + + public: + FileLineEdit(QWidget *parent = nullptr); + ~FileLineEdit(); + + void completeDirectoriesOnly(bool completeDirsOnly) override; + void setFilenameFilters(const QStringList &filters) override; + void setBrowseAction(QAction *action) override; + QWidget *widget() override; + + protected: + void keyPressEvent(QKeyEvent *event) override; + void contextMenuEvent(QContextMenuEvent *event) override; + + private slots: + void showCompletionPopup(); + + private: + QFileSystemModel *m_completerModel; + QCompleter *m_completer; + QAction *m_browseAction; + QFileIconProvider m_iconProvider; + }; + + + class FileComboEdit: public QComboBox, public FileEditorWithCompletion + { + Q_OBJECT + + public: + FileComboEdit(QWidget *parent = nullptr); + + void completeDirectoriesOnly(bool completeDirsOnly) override; + void setFilenameFilters(const QStringList &filters) override; + void setBrowseAction(QAction *action) override; + QWidget *widget() override; + + protected: + QString text() const; + }; +} + +#endif // QBT_GUI_FSPATHEDIT_P_H diff --git a/src/gui/gui.pri b/src/gui/gui.pri index 5cb464ed7..85673e271 100644 --- a/src/gui/gui.pri +++ b/src/gui/gui.pri @@ -56,7 +56,9 @@ HEADERS += \ $$PWD/rss/articlelistwidget.h \ $$PWD/rss/feedlistwidget.h \ $$PWD/rss/automatedrssdownloader.h \ - $$PWD/rss/htmlbrowser.h + $$PWD/rss/htmlbrowser.h \ + $$PWD/fspathedit.h \ + $$PWD/fspathedit_p.h \ SOURCES += \ $$PWD/mainwindow.cpp \ @@ -104,7 +106,9 @@ SOURCES += \ $$PWD/rss/articlelistwidget.cpp \ $$PWD/rss/feedlistwidget.cpp \ $$PWD/rss/automatedrssdownloader.cpp \ - $$PWD/rss/htmlbrowser.cpp + $$PWD/rss/htmlbrowser.cpp \ + $$PWD/fspathedit.cpp \ + $$PWD/fspathedit_p.cpp win32|macx { HEADERS += $$PWD/programupdater.h diff --git a/src/gui/optionsdlg.cpp b/src/gui/optionsdlg.cpp index ebef4073c..c639406c6 100644 --- a/src/gui/optionsdlg.cpp +++ b/src/gui/optionsdlg.cpp @@ -196,7 +196,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(m_ui->checkAssociateMagnetLinks, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); #endif connect(m_ui->checkFileLog, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); - connect(m_ui->textFileLogPath, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(m_ui->textFileLogPath, SIGNAL(selectedPathChanged(QString)), this, SLOT(enableApplyButton())); connect(m_ui->checkFileLogBackup, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->checkFileLogBackup, SIGNAL(toggled(bool)), m_ui->spinFileLogSize, SLOT(setEnabled(bool))); connect(m_ui->checkFileLogDelete, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); @@ -206,13 +206,13 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(m_ui->spinFileLogAge, SIGNAL(valueChanged(int)), this, SLOT(enableApplyButton())); connect(m_ui->comboFileLogAgeType, SIGNAL(currentIndexChanged(int)), this, SLOT(enableApplyButton())); // Downloads tab - connect(m_ui->textSavePath, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(m_ui->textSavePath, SIGNAL(selectedPathChanged(QString)), this, SLOT(enableApplyButton())); connect(m_ui->checkUseSubcategories, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->comboSavingMode, SIGNAL(currentIndexChanged(int)), this, SLOT(enableApplyButton())); connect(m_ui->comboTorrentCategoryChanged, SIGNAL(currentIndexChanged(int)), this, SLOT(enableApplyButton())); connect(m_ui->comboCategoryDefaultPathChanged, SIGNAL(currentIndexChanged(int)), this, SLOT(enableApplyButton())); connect(m_ui->comboCategoryChanged, SIGNAL(currentIndexChanged(int)), this, SLOT(enableApplyButton())); - connect(m_ui->textTempPath, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(m_ui->textTempPath, SIGNAL(selectedPathChanged(QString)), this, SLOT(enableApplyButton())); connect(m_ui->checkAppendqB, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->checkPreallocateAll, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->checkAdditionDialog, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); @@ -223,17 +223,14 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(m_ui->deleteCancelledTorrentBox, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->checkExportDir, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->checkExportDir, SIGNAL(toggled(bool)), m_ui->textExportDir, SLOT(setEnabled(bool))); - connect(m_ui->checkExportDir, SIGNAL(toggled(bool)), m_ui->browseExportDirButton, SLOT(setEnabled(bool))); connect(m_ui->checkExportDirFin, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->checkExportDirFin, SIGNAL(toggled(bool)), m_ui->textExportDirFin, SLOT(setEnabled(bool))); - connect(m_ui->checkExportDirFin, SIGNAL(toggled(bool)), m_ui->browseExportDirFinButton, SLOT(setEnabled(bool))); - connect(m_ui->textExportDir, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(m_ui->textExportDirFin, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(m_ui->textExportDir, SIGNAL(selectedPathChanged(QString)), this, SLOT(enableApplyButton())); + connect(m_ui->textExportDirFin, SIGNAL(selectedPathChanged(QString)), this, SLOT(enableApplyButton())); connect(m_ui->actionTorrentDlOnDblClBox, SIGNAL(currentIndexChanged(int)), this, SLOT(enableApplyButton())); connect(m_ui->actionTorrentFnOnDblClBox, SIGNAL(currentIndexChanged(int)), this, SLOT(enableApplyButton())); connect(m_ui->checkTempFolder, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->checkTempFolder, SIGNAL(toggled(bool)), m_ui->textTempPath, SLOT(setEnabled(bool))); - connect(m_ui->checkTempFolder, SIGNAL(toggled(bool)), m_ui->browseTempDirButton, SLOT(setEnabled(bool))); connect(m_ui->addScanFolderButton, SIGNAL(clicked()), this, SLOT(enableApplyButton())); connect(m_ui->removeScanFolderButton, SIGNAL(clicked()), this, SLOT(enableApplyButton())); connect(m_ui->groupMailNotification, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); @@ -244,7 +241,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(m_ui->mailNotifUsername, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(m_ui->mailNotifPassword, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(m_ui->autoRunBox, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); - connect(m_ui->autoRun_txt, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(m_ui->autoRun_txt, SIGNAL(selectedPathChanged(QString)), this, SLOT(enableApplyButton())); const QString autoRunStr = QString::fromUtf8("%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10\n%11") .arg(tr("Supported parameters (case sensitive):")) @@ -311,7 +308,6 @@ OptionsDialog::OptionsDialog(QWidget *parent) // Misc tab connect(m_ui->checkIPFilter, SIGNAL(toggled(bool)), this, SLOT(enableApplyButton())); connect(m_ui->checkIPFilter, SIGNAL(toggled(bool)), m_ui->textFilterPath, SLOT(setEnabled(bool))); - connect(m_ui->checkIPFilter, SIGNAL(toggled(bool)), m_ui->browseFilterButton, SLOT(setEnabled(bool))); connect(m_ui->checkIPFilter, SIGNAL(toggled(bool)), m_ui->IpFilterRefreshBtn, SLOT(setEnabled(bool))); connect(m_ui->checkIpFilterTrackers, SIGNAL(toggled(bool)), SLOT(enableApplyButton())); connect(m_ui->textFilterPath, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); @@ -357,6 +353,25 @@ OptionsDialog::OptionsDialog(QWidget *parent) m_ui->advPageLayout->addWidget(advancedSettings); connect(advancedSettings, SIGNAL(settingsChanged()), this, SLOT(enableApplyButton())); + m_ui->textFileLogPath->setDialogCaption(tr("Choose a save directory")); + m_ui->textFileLogPath->setMode(FileSystemPathEdit::Mode::DirectorySave); + + m_ui->textExportDir->setDialogCaption(tr("Choose export directory")); + m_ui->textExportDir->setMode(FileSystemPathEdit::Mode::DirectorySave); + + m_ui->textExportDirFin->setDialogCaption(tr("Choose export directory")); + m_ui->textExportDirFin->setMode(FileSystemPathEdit::Mode::DirectorySave); + + m_ui->textFilterPath->setDialogCaption(tr("Choose an IP filter file")); + m_ui->textFilterPath->setFileNameFilter(tr("All supported filters") + + QLatin1String(" (*.dat *.p2p *.p2b);;.dat (*.dat);;.p2p (*.p2p);;.p2b (*.p2b)")); + + m_ui->textSavePath->setDialogCaption(tr("Choose a save directory")); + m_ui->textSavePath->setMode(FileSystemPathEdit::Mode::DirectorySave); + + m_ui->textTempPath->setDialogCaption(tr("Choose a save directory")); + m_ui->textTempPath->setMode(FileSystemPathEdit::Mode::DirectorySave); + show(); loadWindowState(); } @@ -481,7 +496,7 @@ void OptionsDialog::saveOptions() } #endif Application * const app = static_cast(QCoreApplication::instance()); - app->setFileLoggerPath(Utils::Fs::fromNativePath(m_ui->textFileLogPath->text())); + app->setFileLoggerPath(m_ui->textFileLogPath->selectedPath()); app->setFileLoggerBackup(m_ui->checkFileLogBackup->isChecked()); app->setFileLoggerMaxSize(m_ui->spinFileLogSize->value()); app->setFileLoggerAge(m_ui->spinFileLogAge->value()); @@ -498,14 +513,14 @@ void OptionsDialog::saveOptions() auto session = BitTorrent::Session::instance(); // Downloads preferences - session->setDefaultSavePath(Utils::Fs::expandPathAbs(m_ui->textSavePath->text())); + session->setDefaultSavePath(Utils::Fs::expandPathAbs(m_ui->textSavePath->selectedPath())); session->setSubcategoriesEnabled(m_ui->checkUseSubcategories->isChecked()); session->setAutoTMMDisabledByDefault(m_ui->comboSavingMode->currentIndex() == 0); session->setDisableAutoTMMWhenCategoryChanged(m_ui->comboTorrentCategoryChanged->currentIndex() == 1); session->setDisableAutoTMMWhenCategorySavePathChanged(m_ui->comboCategoryChanged->currentIndex() == 1); session->setDisableAutoTMMWhenDefaultSavePathChanged(m_ui->comboCategoryDefaultPathChanged->currentIndex() == 1); session->setTempPathEnabled(m_ui->checkTempFolder->isChecked()); - session->setTempPath(Utils::Fs::expandPathAbs(m_ui->textTempPath->text())); + session->setTempPath(Utils::Fs::expandPathAbs(m_ui->textTempPath->selectedPath())); session->setAppendExtensionEnabled(m_ui->checkAppendqB->isChecked()); session->setPreallocationEnabled(preAllocateAllFiles()); AddNewTorrentDialog::setEnabled(useAdditionDialog()); @@ -527,7 +542,7 @@ void OptionsDialog::saveOptions() pref->setMailNotificationSMTPUsername(m_ui->mailNotifUsername->text()); pref->setMailNotificationSMTPPassword(m_ui->mailNotifPassword->text()); pref->setAutoRunEnabled(m_ui->autoRunBox->isChecked()); - pref->setAutoRunProgram(m_ui->autoRun_txt->text().trimmed()); + pref->setAutoRunProgram(m_ui->autoRun_txt->selectedPath().trimmed()); pref->setActionOnDblClOnTorrentDl(getActionOnDblClOnTorrentDl()); pref->setActionOnDblClOnTorrentFn(getActionOnDblClOnTorrentFn()); TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never @@ -588,7 +603,7 @@ void OptionsDialog::saveOptions() // * IPFilter session->setIPFilteringEnabled(isIPFilteringEnabled()); session->setTrackerFilteringEnabled(m_ui->checkIpFilterTrackers->isChecked()); - session->setIPFilterFile(m_ui->textFilterPath->text()); + session->setIPFilterFile(m_ui->textFilterPath->selectedPath()); // End IPFilter preferences // Queueing system session->setQueueingSystemEnabled(isQueueingSystemEnabled()); @@ -694,7 +709,7 @@ void OptionsDialog::loadOptions() const Application * const app = static_cast(QCoreApplication::instance()); m_ui->checkFileLog->setChecked(app->isFileLoggerEnabled()); - m_ui->textFileLogPath->setText(Utils::Fs::toNativePath(app->fileLoggerPath())); + m_ui->textFileLogPath->setSelectedPath(app->fileLoggerPath()); fileLogBackup = app->isFileLoggerBackup(); m_ui->checkFileLogBackup->setChecked(fileLogBackup); m_ui->spinFileLogSize->setEnabled(fileLogBackup); @@ -723,7 +738,7 @@ void OptionsDialog::loadOptions() m_ui->deleteTorrentBox->setChecked(autoDeleteMode != TorrentFileGuard::Never); m_ui->deleteCancelledTorrentBox->setChecked(autoDeleteMode == TorrentFileGuard::Always); - m_ui->textSavePath->setText(Utils::Fs::toNativePath(session->defaultSavePath())); + m_ui->textSavePath->setSelectedPath(session->defaultSavePath()); m_ui->checkUseSubcategories->setChecked(session->isSubcategoriesEnabled()); m_ui->comboSavingMode->setCurrentIndex(!session->isAutoTMMDisabledByDefault()); m_ui->comboTorrentCategoryChanged->setCurrentIndex(session->isDisableAutoTMMWhenCategoryChanged()); @@ -731,39 +746,35 @@ void OptionsDialog::loadOptions() m_ui->comboCategoryDefaultPathChanged->setCurrentIndex(session->isDisableAutoTMMWhenDefaultSavePathChanged()); m_ui->checkTempFolder->setChecked(session->isTempPathEnabled()); m_ui->textTempPath->setEnabled(m_ui->checkTempFolder->isChecked()); - m_ui->browseTempDirButton->setEnabled(m_ui->checkTempFolder->isChecked()); - m_ui->textTempPath->setText(Utils::Fs::toNativePath(session->tempPath())); + m_ui->textTempPath->setEnabled(m_ui->checkTempFolder->isChecked()); + m_ui->textTempPath->setSelectedPath(Utils::Fs::toNativePath(session->tempPath())); m_ui->checkAppendqB->setChecked(session->isAppendExtensionEnabled()); m_ui->checkPreallocateAll->setChecked(session->isPreallocationEnabled()); - strValue = Utils::Fs::toNativePath(session->torrentExportDirectory()); + strValue = session->torrentExportDirectory(); if (strValue.isEmpty()) { // Disable m_ui->checkExportDir->setChecked(false); m_ui->textExportDir->setEnabled(false); - m_ui->browseExportDirButton->setEnabled(false); } else { // Enable m_ui->checkExportDir->setChecked(true); m_ui->textExportDir->setEnabled(true); - m_ui->browseExportDirButton->setEnabled(true); - m_ui->textExportDir->setText(strValue); + m_ui->textExportDir->setSelectedPath(strValue); } - strValue = Utils::Fs::toNativePath(session->finishedTorrentExportDirectory()); + strValue = session->finishedTorrentExportDirectory(); if (strValue.isEmpty()) { // Disable m_ui->checkExportDirFin->setChecked(false); m_ui->textExportDirFin->setEnabled(false); - m_ui->browseExportDirFinButton->setEnabled(false); } else { // Enable m_ui->checkExportDirFin->setChecked(true); m_ui->textExportDirFin->setEnabled(true); - m_ui->browseExportDirFinButton->setEnabled(true); - m_ui->textExportDirFin->setText(strValue); + m_ui->textExportDirFin->setSelectedPath(strValue); } m_ui->groupMailNotification->setChecked(pref->isMailNotificationEnabled()); @@ -775,7 +786,7 @@ void OptionsDialog::loadOptions() m_ui->mailNotifPassword->setText(pref->getMailNotificationSMTPPassword()); m_ui->autoRunBox->setChecked(pref->isAutoRunEnabled()); - m_ui->autoRun_txt->setText(pref->getAutoRunProgram()); + m_ui->autoRun_txt->setSelectedPath(pref->getAutoRunProgram()); intValue = pref->getActionOnDblClOnTorrentDl(); if (intValue >= m_ui->actionTorrentDlOnDblClBox->count()) intValue = 0; @@ -880,8 +891,7 @@ void OptionsDialog::loadOptions() m_ui->checkIPFilter->setChecked(session->isIPFilteringEnabled()); m_ui->textFilterPath->setEnabled(m_ui->checkIPFilter->isChecked()); - m_ui->textFilterPath->setText(Utils::Fs::toNativePath(session->IPFilterFile())); - m_ui->browseFilterButton->setEnabled(m_ui->checkIPFilter->isChecked()); + m_ui->textFilterPath->setSelectedPath(session->IPFilterFile()); m_ui->IpFilterRefreshBtn->setEnabled(m_ui->checkIPFilter->isChecked()); m_ui->checkIpFilterTrackers->setChecked(session->isTrackerFilteringEnabled()); // End Connection preferences @@ -1332,14 +1342,14 @@ void OptionsDialog::setLocale(const QString &localeStr) QString OptionsDialog::getTorrentExportDir() const { if (m_ui->checkExportDir->isChecked()) - return Utils::Fs::expandPathAbs(m_ui->textExportDir->text()); + return Utils::Fs::expandPathAbs(m_ui->textExportDir->selectedPath()); return QString(); } QString OptionsDialog::getFinishedTorrentExportDir() const { if (m_ui->checkExportDirFin->isChecked()) - return Utils::Fs::expandPathAbs(m_ui->textExportDirFin->text()); + return Utils::Fs::expandPathAbs(m_ui->textExportDirFin->selectedPath()); return QString(); } @@ -1420,73 +1430,10 @@ QString OptionsDialog::askForExportDir(const QString& currentExportPath) return dir; } -void OptionsDialog::on_browseFileLogDir_clicked() -{ - const QString path = Utils::Fs::expandPathAbs(Utils::Fs::fromNativePath(m_ui->textFileLogPath->text())); - QDir pathDir(path); - QString dir; - if (!path.isEmpty() && pathDir.exists()) - dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), pathDir.absolutePath()); - else - dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), QDir::homePath()); - if (!dir.isNull()) - m_ui->textFileLogPath->setText(Utils::Fs::toNativePath(dir)); -} - -void OptionsDialog::on_browseExportDirButton_clicked() -{ - const QString newExportDir = askForExportDir(m_ui->textExportDir->text()); - if (!newExportDir.isNull()) - m_ui->textExportDir->setText(Utils::Fs::toNativePath(newExportDir)); -} - -void OptionsDialog::on_browseExportDirFinButton_clicked() -{ - const QString newExportDir = askForExportDir(m_ui->textExportDirFin->text()); - if (!newExportDir.isNull()) - m_ui->textExportDirFin->setText(Utils::Fs::toNativePath(newExportDir)); -} - -void OptionsDialog::on_browseFilterButton_clicked() -{ - QDir lastDir(Utils::Fs::fromNativePath(m_ui->textFilterPath->text())); - QString lastPath = lastDir.exists() ? lastDir.absolutePath() : QDir::homePath(); - QString newPath = QFileDialog::getOpenFileName(this, tr("Choose an IP filter file"), lastPath, tr("All supported filters") + QString(" (*.dat *.p2p *.p2b);;.dat (*.dat);;.p2p (*.p2p);;.p2b (*.p2b)")); - if (!newPath.isEmpty()) - m_ui->textFilterPath->setText(Utils::Fs::toNativePath(newPath)); -} - -// Display dialog to choose save dir -void OptionsDialog::on_browseSaveDirButton_clicked() -{ - const QString save_path = Utils::Fs::expandPathAbs(m_ui->textSavePath->text()); - QDir saveDir(save_path); - QString dir; - if (!save_path.isEmpty() && saveDir.exists()) - dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), saveDir.absolutePath()); - else - dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), QDir::homePath()); - if (!dir.isNull()) - m_ui->textSavePath->setText(Utils::Fs::toNativePath(dir)); -} - -void OptionsDialog::on_browseTempDirButton_clicked() -{ - const QString temp_path = Utils::Fs::expandPathAbs(m_ui->textTempPath->text()); - QDir tempDir(temp_path); - QString dir; - if (!temp_path.isEmpty() && tempDir.exists()) - dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), tempDir.absolutePath()); - else - dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), QDir::homePath()); - if (!dir.isNull()) - m_ui->textTempPath->setText(Utils::Fs::toNativePath(dir)); -} - // Return Filter object to apply to BT session QString OptionsDialog::getFilter() const { - return Utils::Fs::fromNativePath(m_ui->textFilterPath->text()); + return m_ui->textFilterPath->selectedPath(); } // Web UI diff --git a/src/gui/optionsdlg.h b/src/gui/optionsdlg.h index 294a3c90c..3419fce85 100644 --- a/src/gui/optionsdlg.h +++ b/src/gui/optionsdlg.h @@ -95,12 +95,6 @@ private slots: void on_IpFilterRefreshBtn_clicked(); void handleIPFilterParsed(bool error, int ruleCount); void on_banListButton_clicked(); - void on_browseFileLogDir_clicked(); - void on_browseExportDirButton_clicked(); - void on_browseExportDirFinButton_clicked(); - void on_browseFilterButton_clicked(); - void on_browseSaveDirButton_clicked(); - void on_browseTempDirButton_clicked(); void on_randomButton_clicked(); void on_addScanFolderButton_clicked(); void on_removeScanFolderButton_clicked(); diff --git a/src/gui/optionsdlg.ui b/src/gui/optionsdlg.ui index b4989b375..9ab7a0d38 100644 --- a/src/gui/optionsdlg.ui +++ b/src/gui/optionsdlg.ui @@ -6,8 +6,8 @@ 0 0 - 779 - 591 + 1116 + 838 @@ -90,7 +90,7 @@ - 0 + 1 @@ -390,7 +390,7 @@ - Show qBittorrent in notification area + Show &qBittorrent in notification area true @@ -491,7 +491,7 @@ - Log file + &Log file true @@ -504,26 +504,19 @@ + + + 0 + 0 + + Save path: - - - - - - - 0 - 25 - - - - ... - - + @@ -692,7 +685,7 @@ - Display torrent content and some options + Display &torrent content and some options true @@ -737,7 +730,7 @@ Should the .torrent file be deleted after adding it - Delete .torrent files afterwards + De&lete .torrent files afterwards true @@ -969,91 +962,48 @@ - - - - Default Save Path: - - - - - - - 0 - 0 - - - - - - + + + + + - - - true - - - - 22 - 22 - - - - - 25 - 27 - - - - ... - - + - - + + + + + + + + + - Keep incomplete torrents in: + Copy .torrent files for finished downloads to: - - - - - - - 25 - 27 - - - - - 22 - 22 - - - - - 25 - 27 - - - - ... - - + + + + + Default Save Path: + + + @@ -1061,65 +1011,13 @@ - - - - - - - - - - 22 - 22 - - - - - 25 - 27 - - - - ... - - - - - - - + + - Copy .torrent files for finished downloads to: + Keep incomplete torrents in: - - - - - - - - - - 22 - 22 - - - - - 25 - 27 - - - - ... - - - - - @@ -1226,7 +1124,7 @@ - Email notification upon download completion + Email notification &upon download completion true @@ -1311,7 +1209,7 @@ - Run external program on torrent completion + Run e&xternal program on torrent completion true @@ -1321,7 +1219,7 @@ - + @@ -1681,7 +1579,7 @@ false - Authentication + A&uthentication true @@ -1734,7 +1632,7 @@ - IP Filtering + IP Fi&ltering @@ -1747,20 +1645,7 @@ - - - - - - - 0 - 25 - - - - ... - - + @@ -1946,7 +1831,7 @@ - Schedule the use of alternative rate limits + Schedule &the use of alternative rate limits true @@ -2363,7 +2248,7 @@ - Torrent Queueing + &Torrent Queueing true @@ -2562,7 +2447,7 @@ - Automatically add these trackers to new downloads: + A&utomatically add these trackers to new downloads: true @@ -2813,7 +2698,7 @@ - Use HTTPS instead of HTTP + &Use HTTPS instead of HTTP true @@ -3000,7 +2885,7 @@ - Update my dynamic domain name + Upda&te my dynamic domain name true @@ -3139,11 +3024,17 @@ + + + FileSystemPathLineEdit + QWidget +
fspathedit.h
+ 1 +
+
tabOption comboI18n - textSavePath - browseSaveDirButton checkStartPaused spinPort checkUPnP