Sync translations from Transifex and run lupdate
[qBittorrent.git] / src / gui / fspathedit.cpp
blobbe8e15c167d43405a8adde8cf07d421539a1d14f
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2016 Eugene Shalygin
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * In addition, as a special exception, the copyright holders give permission to
20 * link this program with the OpenSSL project's "OpenSSL" library (or with
21 * modified versions of it that use the same license as the "OpenSSL" library),
22 * and distribute the linked executables. You must obey the GNU General Public
23 * License in all respects for all of the code used other than "OpenSSL". If you
24 * modify file(s), you may extend this exception to your version of the file(s),
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
29 #include "fspathedit.h"
31 #include <memory>
32 #include <stdexcept>
34 #include <QAction>
35 #include <QApplication>
36 #include <QCoreApplication>
37 #include <QFileDialog>
38 #include <QHBoxLayout>
39 #include <QStyle>
40 #include <QToolButton>
42 #include "base/utils/fs.h"
43 #include "fspathedit_p.h"
45 namespace
47 struct TrStringWithComment
49 const char *source;
50 const char *comment;
52 QString tr() const
54 return QCoreApplication::translate("FileSystemPathEdit", source, comment);
58 constexpr TrStringWithComment browseButtonBriefText =
59 QT_TRANSLATE_NOOP3("FileSystemPathEdit", "...", "Launch file dialog button text (brief)");
60 constexpr TrStringWithComment browseButtonFullText =
61 QT_TRANSLATE_NOOP3("FileSystemPathEdit", "&Browse...", "Launch file dialog button text (full)");
62 constexpr TrStringWithComment defaultDialogCaptionForFile =
63 QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a file", "Caption for file open/save dialog");
64 constexpr TrStringWithComment defaultDialogCaptionForDirectory =
65 QT_TRANSLATE_NOOP3("FileSystemPathEdit", "Choose a folder", "Caption for directory open dialog");
68 class FileSystemPathEdit::FileSystemPathEditPrivate
70 Q_DECLARE_PUBLIC(FileSystemPathEdit)
71 Q_DISABLE_COPY_MOVE(FileSystemPathEditPrivate)
73 FileSystemPathEditPrivate(FileSystemPathEdit *q, Private::FileEditorWithCompletion *editor);
75 void modeChanged();
76 void browseActionTriggered();
77 QString dialogCaptionOrDefault() const;
79 FileSystemPathEdit *q_ptr;
80 std::unique_ptr<Private::FileEditorWithCompletion> m_editor;
81 QAction *m_browseAction;
82 QToolButton *m_browseBtn;
83 QString m_fileNameFilter;
84 Mode m_mode;
85 QString m_lastSignaledPath;
86 QString m_dialogCaption;
87 Private::FileSystemPathValidator *m_validator;
90 FileSystemPathEdit::FileSystemPathEditPrivate::FileSystemPathEditPrivate(
91 FileSystemPathEdit *q, Private::FileEditorWithCompletion *editor)
92 : q_ptr {q}
93 , m_editor {editor}
94 , m_browseAction {new QAction(q)}
95 , m_browseBtn {new QToolButton(q)}
96 , m_mode {FileSystemPathEdit::Mode::FileOpen}
97 , m_validator {new Private::FileSystemPathValidator(q)}
99 m_browseAction->setIconText(browseButtonBriefText.tr());
100 m_browseAction->setText(browseButtonFullText.tr());
101 m_browseAction->setToolTip(browseButtonFullText.tr().remove(QLatin1Char('&')));
102 m_browseAction->setShortcut(Qt::CTRL + Qt::Key_B);
103 m_browseBtn->setDefaultAction(m_browseAction);
104 m_fileNameFilter = tr("Any file") + QLatin1String(" (*)");
105 m_editor->setBrowseAction(m_browseAction);
106 m_validator->setStrictMode(false);
107 m_editor->setValidator(m_validator);
108 modeChanged();
111 void FileSystemPathEdit::FileSystemPathEditPrivate::browseActionTriggered()
113 Q_Q(FileSystemPathEdit);
114 QString filter = q->fileNameFilter();
115 QString directory = q->currentDirectory().isEmpty() ? QDir::homePath() : q->currentDirectory();
117 QString selectedPath;
118 switch (m_mode)
120 case FileSystemPathEdit::Mode::FileOpen:
121 selectedPath = QFileDialog::getOpenFileName(q, dialogCaptionOrDefault(), directory, filter);
122 break;
123 case FileSystemPathEdit::Mode::FileSave:
124 selectedPath = QFileDialog::getSaveFileName(q, dialogCaptionOrDefault(), directory, filter, &filter);
125 break;
126 case FileSystemPathEdit::Mode::DirectoryOpen:
127 case FileSystemPathEdit::Mode::DirectorySave:
128 selectedPath = QFileDialog::getExistingDirectory(q, dialogCaptionOrDefault(),
129 directory, QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly);
130 break;
131 default:
132 throw std::logic_error("Unknown FileSystemPathEdit mode");
134 if (!selectedPath.isEmpty())
135 q->setEditWidgetText(Utils::Fs::toNativePath(selectedPath));
138 QString FileSystemPathEdit::FileSystemPathEditPrivate::dialogCaptionOrDefault() const
140 if (!m_dialogCaption.isEmpty())
141 return m_dialogCaption;
143 switch (m_mode)
145 case FileSystemPathEdit::Mode::FileOpen:
146 case FileSystemPathEdit::Mode::FileSave:
147 return defaultDialogCaptionForFile.tr();
148 case FileSystemPathEdit::Mode::DirectoryOpen:
149 case FileSystemPathEdit::Mode::DirectorySave:
150 return defaultDialogCaptionForDirectory.tr();
151 default:
152 throw std::logic_error("Unknown FileSystemPathEdit mode");
156 void FileSystemPathEdit::FileSystemPathEditPrivate::modeChanged()
158 bool showDirsOnly = false;
159 switch (m_mode)
161 case FileSystemPathEdit::Mode::FileOpen:
162 case FileSystemPathEdit::Mode::FileSave:
163 showDirsOnly = false;
164 break;
165 case FileSystemPathEdit::Mode::DirectoryOpen:
166 case FileSystemPathEdit::Mode::DirectorySave:
167 showDirsOnly = true;
168 break;
169 default:
170 throw std::logic_error("Unknown FileSystemPathEdit mode");
172 m_browseAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon));
173 m_editor->completeDirectoriesOnly(showDirsOnly);
175 m_validator->setExistingOnly(m_mode != FileSystemPathEdit::Mode::FileSave);
176 m_validator->setDirectoriesOnly((m_mode == FileSystemPathEdit::Mode::DirectoryOpen) || (m_mode == FileSystemPathEdit::Mode::DirectorySave));
177 m_validator->setCheckReadPermission((m_mode == FileSystemPathEdit::Mode::FileOpen) || (m_mode == FileSystemPathEdit::Mode::DirectoryOpen));
178 m_validator->setCheckWritePermission((m_mode == FileSystemPathEdit::Mode::FileSave) || (m_mode == FileSystemPathEdit::Mode::DirectorySave));
181 FileSystemPathEdit::FileSystemPathEdit(Private::FileEditorWithCompletion *editor, QWidget *parent)
182 : QWidget(parent)
183 , d_ptr(new FileSystemPathEditPrivate(this, editor))
185 Q_D(FileSystemPathEdit);
186 editor->widget()->setParent(this);
188 auto *layout = new QHBoxLayout(this);
189 layout->setContentsMargins(0, 0, 0, 0);
190 layout->addWidget(editor->widget());
191 layout->addWidget(d->m_browseBtn);
193 connect(d->m_browseAction, &QAction::triggered, this, [this]() { this->d_func()->browseActionTriggered(); });
196 FileSystemPathEdit::~FileSystemPathEdit()
198 delete d_ptr;
201 QString FileSystemPathEdit::selectedPath() const
203 return Utils::Fs::toUniformPath(editWidgetText());
206 void FileSystemPathEdit::setSelectedPath(const QString &val)
208 Q_D(FileSystemPathEdit);
209 setEditWidgetText(Utils::Fs::toNativePath(val));
210 d->m_editor->widget()->setToolTip(val);
213 QString FileSystemPathEdit::fileNameFilter() const
215 Q_D(const FileSystemPathEdit);
216 return d->m_fileNameFilter;
219 void FileSystemPathEdit::setFileNameFilter(const QString &val)
221 Q_D(FileSystemPathEdit);
222 d->m_fileNameFilter = val;
224 #if 0
225 // QFileSystemModel applies name filters to directories too.
226 // To use the filters we have to subclass QFileSystemModel and skip directories while filtering
227 // extract file masks
228 const int openBracePos = val.indexOf(QLatin1Char('('), 0);
229 const int closeBracePos = val.indexOf(QLatin1Char(')'), openBracePos + 1);
230 if ((openBracePos > 0) && (closeBracePos > 0) && (closeBracePos > openBracePos + 2))
232 QString filterString = val.mid(openBracePos + 1, closeBracePos - openBracePos - 1);
233 if (filterString == QLatin1String("*"))
234 { // no filters
235 d->m_editor->setFilenameFilters({});
237 else
239 QStringList filters = filterString.split(QLatin1Char(' '), Qt::SkipEmptyParts);
240 d->m_editor->setFilenameFilters(filters);
243 else
245 d->m_editor->setFilenameFilters({});
247 #endif
250 bool FileSystemPathEdit::briefBrowseButtonCaption() const
252 Q_D(const FileSystemPathEdit);
253 return d->m_browseBtn->text() == browseButtonBriefText.tr();
256 void FileSystemPathEdit::setBriefBrowseButtonCaption(bool brief)
258 Q_D(FileSystemPathEdit);
259 d->m_browseBtn->setText(brief ? browseButtonBriefText.tr() : browseButtonFullText.tr());
262 void FileSystemPathEdit::onPathEdited()
264 Q_D(FileSystemPathEdit);
265 QString newPath = selectedPath();
266 if (newPath != d->m_lastSignaledPath)
268 emit selectedPathChanged(newPath);
269 d->m_lastSignaledPath = newPath;
270 d->m_editor->widget()->setToolTip(editWidgetText());
274 FileSystemPathEdit::Mode FileSystemPathEdit::mode() const
276 Q_D(const FileSystemPathEdit);
277 return d->m_mode;
280 void FileSystemPathEdit::setMode(FileSystemPathEdit::Mode theMode)
282 Q_D(FileSystemPathEdit);
283 d->m_mode = theMode;
284 d->modeChanged();
287 QString FileSystemPathEdit::dialogCaption() const
289 Q_D(const FileSystemPathEdit);
290 return d->m_dialogCaption;
293 void FileSystemPathEdit::setDialogCaption(const QString &caption)
295 Q_D(FileSystemPathEdit);
296 d->m_dialogCaption = caption;
299 QString FileSystemPathEdit::currentDirectory() const
301 return QFileInfo(selectedPath()).absoluteDir().absolutePath();
304 QWidget *FileSystemPathEdit::editWidgetImpl() const
306 Q_D(const FileSystemPathEdit);
307 return d->m_editor->widget();
310 // ------------------------- FileSystemPathLineEdit ----------------------
311 FileSystemPathLineEdit::FileSystemPathLineEdit(QWidget *parent)
312 : FileSystemPathEdit(new WidgetType(), parent)
314 connect(editWidget<WidgetType>(), &QLineEdit::editingFinished, this, &FileSystemPathLineEdit::onPathEdited);
315 connect(editWidget<WidgetType>(), &QLineEdit::textChanged, this, &FileSystemPathLineEdit::onPathEdited);
318 QString FileSystemPathLineEdit::editWidgetText() const
320 return editWidget<WidgetType>()->text();
323 void FileSystemPathLineEdit::clear()
325 editWidget<WidgetType>()->clear();
328 void FileSystemPathLineEdit::setEditWidgetText(const QString &text)
330 editWidget<WidgetType>()->setText(text);
333 // ----------------------- FileSystemPathComboEdit -----------------------
334 FileSystemPathComboEdit::FileSystemPathComboEdit(QWidget *parent)
335 : FileSystemPathEdit(new WidgetType(), parent)
337 editWidget<WidgetType>()->setEditable(true);
338 connect(editWidget<WidgetType>(), &QComboBox::currentTextChanged, this, &FileSystemPathComboEdit::onPathEdited);
339 connect(editWidget<WidgetType>()->lineEdit(), &QLineEdit::editingFinished, this, &FileSystemPathComboEdit::onPathEdited);
342 void FileSystemPathComboEdit::clear()
344 editWidget<WidgetType>()->clear();
347 int FileSystemPathComboEdit::count() const
349 return editWidget<WidgetType>()->count();
352 QString FileSystemPathComboEdit::item(int index) const
354 return Utils::Fs::toUniformPath(editWidget<WidgetType>()->itemText(index));
357 void FileSystemPathComboEdit::addItem(const QString &text)
359 editWidget<WidgetType>()->addItem(Utils::Fs::toNativePath(text));
362 void FileSystemPathComboEdit::insertItem(int index, const QString &text)
364 editWidget<WidgetType>()->insertItem(index, Utils::Fs::toNativePath(text));
367 int FileSystemPathComboEdit::currentIndex() const
369 return editWidget<WidgetType>()->currentIndex();
372 void FileSystemPathComboEdit::setCurrentIndex(int index)
374 editWidget<WidgetType>()->setCurrentIndex(index);
377 int FileSystemPathComboEdit::maxVisibleItems() const
379 return editWidget<WidgetType>()->maxVisibleItems();
382 void FileSystemPathComboEdit::setMaxVisibleItems(int maxItems)
384 editWidget<WidgetType>()->setMaxVisibleItems(maxItems);
387 QString FileSystemPathComboEdit::editWidgetText() const
389 return editWidget<WidgetType>()->currentText();
392 void FileSystemPathComboEdit::setEditWidgetText(const QString &text)
394 editWidget<WidgetType>()->setCurrentText(text);