15#include "kfilewidget.h"
17#include "../utils_p.h"
18#include "kfilebookmarkhandler_p.h"
19#include "kfileplacesmodel.h"
20#include "kfileplacesview.h"
21#include "kfilepreviewgenerator.h"
22#include "kfilewidgetdocktitlebar_p.h"
23#include "kurlcombobox.h"
24#include "kurlnavigator.h"
25#include "kurlnavigatorbuttonbase_p.h"
27#include <config-kiofilewidgets.h>
29#include <defaults-kfile.h>
30#include <kdiroperator.h>
31#include <kfilefiltercombo.h>
32#include <kfileitemdelegate.h>
34#include <kio/jobuidelegate.h>
35#include <kio/statjob.h>
36#include <kprotocolmanager.h>
37#include <krecentdirs.h>
38#include <krecentdocument.h>
39#include <kurlauthorized.h>
40#include <kurlcompletion.h>
43#include <KConfigGroup>
46#include <KFilePlacesModel>
49#include <KLocalizedString>
51#include <KMessageWidget>
52#include <KSharedConfig>
54#include <KStandardActions>
55#include <KToggleAction>
57#include <QAbstractProxyModel>
58#include <QApplication>
68#include <QLoggingCategory>
70#include <QMimeDatabase>
74#include <QStandardPaths>
80#include <qnamespace.h>
82Q_DECLARE_LOGGING_CATEGORY(KIO_KFILEWIDGETS_FW)
83Q_LOGGING_CATEGORY(KIO_KFILEWIDGETS_FW,
"kf.kio.kfilewidgets.kfilewidget", QtInfoMsg)
85class KFileWidgetPrivate
88 explicit KFileWidgetPrivate(KFileWidget *qq)
95 delete m_bookmarkHandler;
103 QSize screenSize()
const
105 return q->parentWidget() ? q->parentWidget()->screen()->availableGeometry().size()
109 void initDirOpWidgets();
111 void initZoomWidget();
112 void initLocationWidget();
113 void initFilterWidget();
114 void initQuickFilterWidget();
115 void updateLocationWhatsThis();
116 void updateAutoSelectExtension();
117 void initPlacesPanel();
118 void setPlacesViewSplitterSizes();
120 void readViewConfig();
121 void writeViewConfig();
122 void setNonExtSelection();
123 void setLocationText(
const QUrl &);
124 void setLocationText(
const QList<QUrl> &);
125 void appendExtension(QUrl &url);
126 void updateLocationEditExtension(
const QString &);
127 QString findMatchingFilter(
const QString &filter,
const QString &filename)
const;
129 void updateFilterText();
136 QList<QUrl> tokenize(
const QString &line)
const;
140 void readRecentFiles();
144 void saveRecentFiles();
149 void multiSelectionChanged();
154 QUrl getCompleteUrl(
const QString &)
const;
161 bool toOverwrite(
const QUrl &);
164 void slotLocationChanged(
const QString &);
165 void urlEntered(
const QUrl &);
166 void enterUrl(
const QUrl &);
167 void enterUrl(
const QString &);
168 void locationAccepted(
const QString &);
169 void slotMimeFilterChanged();
170 void slotQuickFilterChanged();
171 void fileHighlighted(
const KFileItem &,
bool);
172 void fileSelected(
const KFileItem &);
173 void slotLoadingFinished();
174 void togglePlacesPanel(
bool show, QObject *sender =
nullptr);
175 void toggleBookmarks(
bool);
176 void setQuickFilterVisible(
bool);
177 void slotAutoSelectExtClicked();
178 void placesViewSplitterMoved(
int,
int);
179 void activateUrlNavigator();
185 void changeIconsSize(ZoomState zoom);
186 void slotDirOpIconSizeChanged(
int size);
187 void slotIconSizeSliderMoved(
int);
188 void slotIconSizeChanged(
int);
189 void slotViewDoubleClicked(
const QModelIndex &);
190 void slotViewKeyEnterReturnPressed();
192 void addToRecentDocuments();
194 QString locationEditCurrentText()
const;
195 void updateNameFilter(
const KFileFilter &);
202 QUrl mostLocalUrl(
const QUrl &url);
204 void setInlinePreviewShown(
bool show);
206 KFileWidget *
const q;
213 QBoxLayout *m_boxLayout =
nullptr;
214 QFormLayout *m_lafBox =
nullptr;
216 QLabel *m_locationLabel =
nullptr;
217 QWidget *m_opsWidget =
nullptr;
218 QVBoxLayout *m_opsWidgetLayout =
nullptr;
220 QLabel *m_filterLabel =
nullptr;
221 KUrlNavigator *m_urlNavigator =
nullptr;
222 KMessageWidget *m_messageWidget =
nullptr;
223 QPushButton *m_okButton =
nullptr;
224 QPushButton *m_cancelButton =
nullptr;
225 QDockWidget *m_placesDock =
nullptr;
226 KFilePlacesView *m_placesView =
nullptr;
227 QSplitter *m_placesViewSplitter =
nullptr;
231 int m_placesViewWidth = -1;
233 QWidget *m_labeledCustomWidget =
nullptr;
234 QWidget *m_bottomCustomWidget =
nullptr;
237 QCheckBox *m_autoSelectExtCheckBox =
nullptr;
240 QList<QUrl> m_urlList;
247 KFileBookmarkHandler *m_bookmarkHandler =
nullptr;
249 KActionMenu *m_bookmarkButton =
nullptr;
251 QToolBar *m_toolbar =
nullptr;
252 KUrlComboBox *m_locationEdit =
nullptr;
253 KDirOperator *m_ops =
nullptr;
254 KFileFilterCombo *m_filterWidget =
nullptr;
255 QTimer m_filterDelayTimer;
257 QWidget *m_quickFilter =
nullptr;
258 QLineEdit *m_quickFilterEdit =
nullptr;
259 QToolButton *m_quickFilterLock =
nullptr;
260 QToolButton *m_quickFilterClose =
nullptr;
262 KFilePlacesModel *m_model =
nullptr;
265 bool m_autoSelectExtChecked =
false;
269 bool m_keepLocation =
false;
273 bool m_hasView =
false;
275 bool m_hasDefaultFilter =
false;
276 bool m_inAccept =
false;
277 bool m_confirmOverwrite =
false;
278 bool m_differentHierarchyLevelItemsEntered =
false;
280 const std::array<short, 8> m_stdIconSizes = {
291 QSlider *m_iconSizeSlider =
nullptr;
292 QAction *m_zoomOutAction =
nullptr;
293 QAction *m_zoomInAction =
nullptr;
298 KConfigGroup m_configGroup;
299 KConfigGroup m_stateConfigGroup;
301 KToggleAction *m_toggleBookmarksAction =
nullptr;
302 KToggleAction *m_togglePlacesPanelAction =
nullptr;
303 KToggleAction *m_toggleQuickFilterAction =
nullptr;
306Q_GLOBAL_STATIC(
QUrl, lastDirectory)
309static bool containsProtocolSection(
const QString &
string)
311 int len =
string.length();
312 static const char prot[] =
":/";
313 for (
int i = 0; i < len;) {
319 for (; j >= 0; j--) {
320 const QChar &ch(
string[j]);
321 if (ch.toLatin1() == 0 || !ch.isLetter()) {
324 if (ch.isSpace() && (i - j - 1) >= 2) {
328 if (j < 0 && i >= 2) {
340 if (Utils::isAbsoluteLocalPath(str)) {
344 if (url.isRelative()) {
353 , d(new KFileWidgetPrivate(this))
355 QUrl startDir(_startDir);
361 d->m_okButton->setDefault(
true);
365 d->m_okButton->hide();
366 d->m_cancelButton->hide();
368 d->initDirOpWidgets();
372 d->m_url =
getStartUrl(startDir, d->m_fileClass, filename);
375 const auto operatorActions = d->m_ops->allActions();
376 for (
QAction *action : operatorActions) {
383 d->activateUrlNavigator();
401 d->initLocationWidget();
404 d->initFilterWidget();
406 d->initQuickFilterWidget();
409 d->m_autoSelectExtCheckBox =
new QCheckBox(
this);
411 d->slotAutoSelectExtClicked();
418 config->reparseConfiguration();
424 if (d->m_configGroup.hasKey(RecentURLs)) {
425 d->m_stateConfigGroup.writeEntry(RecentURLs, d->m_configGroup.readEntry(RecentURLs));
426 d->m_configGroup.revertToDefault(RecentURLs);
429 if (d->m_configGroup.hasKey(RecentFiles)) {
430 d->m_stateConfigGroup.writeEntry(RecentFiles, d->m_configGroup.readEntry(RecentFiles));
431 d->m_configGroup.revertToDefault(RecentFiles);
435 d->readRecentFiles();
437 d->m_ops->action(KDirOperator::ShowPreview)->setChecked(d->m_ops->isInlinePreviewShown());
438 d->slotDirOpIconSizeChanged(d->m_ops->iconSize());
447 bool statRes =
false;
451 statRes = statJob->
exec();
460 d->m_ops->setUrl(startDir,
true);
461 d->m_urlNavigator->setLocationUrl(startDir);
462 if (d->m_placesView) {
463 d->m_placesView->setUrl(startDir);
469 QLineEdit *lineEdit = d->m_locationEdit->lineEdit();
472 d->setLocationText(
QUrl(filename));
481 d->m_locationEdit->setFocus();
484 Q_ASSERT(showHiddenAction);
485 d->m_urlNavigator->setShowHiddenFolders(showHiddenAction->
isChecked());
487 d->m_urlNavigator->setShowHiddenFolders(checked);
491 Q_ASSERT(hiddenFilesLastAction);
492 d->m_urlNavigator->setSortHiddenFoldersLast(hiddenFilesLastAction->isChecked());
494 d->m_urlNavigator->setSortHiddenFoldersLast(checked);
502 d->m_ops->removeEventFilter(
this);
503 d->m_locationEdit->removeEventFilter(
this);
508 d->m_locationLabel->setText(text);
513 d->m_ops->clearFilter();
514 d->m_filterWidget->setFilters(filters, activeFilter);
515 d->m_ops->updateDir();
516 d->m_hasDefaultFilter =
false;
517 d->m_filterWidget->setEditable(
true);
518 d->updateFilterText();
520 d->updateAutoSelectExtension();
525 return d->m_filterWidget->currentFilter();
531 d->m_ops->clearFilter();
532 d->m_hasDefaultFilter =
false;
533 d->m_filterWidget->setEditable(
true);
535 d->updateAutoSelectExtension();
540 d->m_ops->setPreviewWidget(w);
541 d->m_ops->clearHistory();
545QUrl KFileWidgetPrivate::getCompleteUrl(
const QString &_url)
const
552 if (Utils::isAbsoluteLocalPath(url)) {
555 QUrl relativeUrlTest(m_ops->url());
556 relativeUrlTest.setPath(Utils::concatPaths(relativeUrlTest.path(), url));
576 const QSize goodSize(48 * fontSize, 30 * fontSize);
577 const QSize scrnSize = d->screenSize();
578 const QSize minSize(scrnSize / 2);
579 const QSize maxSize(scrnSize * qreal(0.9));
601 QList<QUrl> locationEditCurrentTextList(d->tokenize(locationEditCurrentText));
605 if (!((
mode & KFile::File) || (
mode & KFile::Directory) || (
mode & KFile::Files))) {
610 const bool directoryMode = (
mode & KFile::Directory);
611 const bool onlyDirectoryMode = directoryMode && !(
mode & KFile::File) && !(
mode & KFile::Files);
614 d->m_urlList.clear();
618 if (locationEditCurrentTextList.
isEmpty() && !onlyDirectoryMode) {
624 if (locationEditCurrentTextList.
count() > 1) {
625 if (
mode & KFile::File) {
650 if (!d->m_differentHierarchyLevelItemsEntered) {
660 while (!res &&
start < locationEditCurrentTextList.
count()) {
661 topMostUrl = locationEditCurrentTextList.
at(
start);
664 res = statJob->
exec();
678 for (
int i =
start; i < locationEditCurrentTextList.
count(); ++i) {
679 QUrl currUrl = locationEditCurrentTextList.
at(i);
682 int res = statJob->
exec();
698 stringList.
reserve(locationEditCurrentTextList.
count());
699 for (
int i = 0; i < locationEditCurrentTextList.
count(); ++i) {
700 Q_ASSERT(topMostUrl.
isParentOf(locationEditCurrentTextList[i]));
701 QString relativePath = relativePathOrUrl(topMostUrl, locationEditCurrentTextList[i]);
702 stringList << escapeDoubleQuotes(std::move(relativePath));
705 d->m_ops->setUrl(topMostUrl,
true);
706 const bool signalsBlocked = d->m_locationEdit->lineEdit()->blockSignals(
true);
707 d->m_locationEdit->lineEdit()->setText(QStringLiteral(
"\"%1\"").arg(stringList.
join(QStringLiteral(
"\" \""))));
710 d->m_differentHierarchyLevelItemsEntered =
true;
717 }
else if (!locationEditCurrentTextList.
isEmpty()) {
726 if (!locationEditCurrentText.
isEmpty() && !onlyDirectoryMode
727 && (Utils::isAbsoluteLocalPath(locationEditCurrentText) || containsProtocolSection(locationEditCurrentText))) {
728 QUrl url = urlFromString(locationEditCurrentText);
731 if (d->m_operationMode == Opening) {
734 int res = statJob->
exec();
740 Utils::appendSlashToPath(url);
748 int res = statJob->
exec();
757 d->m_ops->setUrl(url,
true);
758 const bool signalsBlocked = d->m_locationEdit->lineEdit()->blockSignals(
true);
759 d->m_locationEdit->lineEdit()->setText(fileName);
764 locationEditCurrentTextList = {url};
770 d->m_differentHierarchyLevelItemsEntered =
false;
776 bool filesInList =
false;
777 while (it != locationEditCurrentTextList.
constEnd()) {
780 if (d->m_operationMode == Saving && !directoryMode) {
781 d->appendExtension(url);
787 int res = statJob->
exec();
796 if ((
mode & KFile::LocalOnly) && !d->mostLocalUrl(d->m_url).isLocalFile()) {
804 i18np(
"The selected URL uses an unsupported scheme. "
805 "Please use the following scheme: %2",
806 "The selected URL uses an unsupported scheme. "
807 "Please use one of the following schemes: %2",
810 i18n(
"Unsupported URL scheme"));
816 d->m_ops->setUrl(url,
true);
817 const bool signalsBlocked = d->m_locationEdit->lineEdit()->blockSignals(
true);
818 d->m_locationEdit->lineEdit()->setText(
QString());
821 }
else if (res && onlyDirectoryMode && !statJob->
statResult().
isDir()) {
824 }
else if (!(
mode & KFile::ExistingOnly) || res) {
836 if ((d->m_operationMode == Saving) && d->m_confirmOverwrite && !d->toOverwrite(url)) {
848void KFileWidget::accept()
850 d->m_inAccept =
true;
852 *lastDirectory() = d->m_ops->url();
853 if (!d->m_fileClass.isEmpty()) {
858 d->m_locationEdit->setItemText(0, QString());
861 int atmost = d->m_locationEdit->maxItems();
862 for (
const auto &url : list) {
873 for (
int i = 1; i < d->m_locationEdit->count(); ++i) {
874 if (d->m_locationEdit->itemText(i) == file) {
875 d->m_locationEdit->removeItem(i--);
882 d->m_locationEdit->insertItem(1, file);
885 d->writeViewConfig();
886 d->saveRecentFiles();
888 d->addToRecentDocuments();
890 if (!(
mode() & KFile::Files)) {
897void KFileWidgetPrivate::fileHighlighted(
const KFileItem &i,
bool isKeyNavigation)
899 if ((m_locationEdit->hasFocus() && !m_locationEdit->currentText().isEmpty())) {
903 if (!i.
isNull() && i.isDir() && !(m_ops->mode() & KFile::Directory)) {
907 const bool modified = m_locationEdit->lineEdit()->isModified();
909 if (!(m_ops->mode() & KFile::Files)) {
912 setLocationText(QUrl());
919 if (!m_locationEdit->hasFocus()) {
920 setLocationText(m_url);
923 Q_EMIT q->fileHighlighted(m_url);
925 multiSelectionChanged();
926 Q_EMIT q->selectionChanged();
929 m_locationEdit->lineEdit()->setModified(
false);
936 if (!isKeyNavigation && m_operationMode == KFileWidget::Saving) {
937 m_locationEdit->setFocus();
941void KFileWidgetPrivate::fileSelected(
const KFileItem &i)
943 if (!i.
isNull() && i.isDir()) {
947 if (!(m_ops->mode() & KFile::Files)) {
949 setLocationText(QUrl());
952 setLocationText(i.targetUrl());
954 multiSelectionChanged();
955 Q_EMIT q->selectionChanged();
959 if (m_operationMode == KFileWidget::Saving) {
960 m_locationEdit->setFocus();
968void KFileWidgetPrivate::multiSelectionChanged()
970 if (m_locationEdit->hasFocus() && !m_locationEdit->currentText().isEmpty()) {
974 const KFileItemList
list = m_ops->selectedItems();
977 setLocationText(QUrl());
983 setLocationText(
list.
first().targetUrl());
988 for (
const auto &item : list) {
990 urlList.
append(item.targetUrl());
993 setLocationText(urlList);
996void KFileWidgetPrivate::setLocationText(
const QUrl &url)
1001 if ((url.
isEmpty() && m_locationEdit->lineEdit()->text().isEmpty()) || m_locationEdit->lineEdit()->text() == escapeDoubleQuotes(url.
fileName())) {
1007 const QSignalBlocker blocker(m_locationEdit);
1013 q->setUrl(directory,
false);
1015 q->setUrl(url,
false);
1018 m_locationEdit->lineEdit()->selectAll();
1019 m_locationEdit->lineEdit()->insert(escapeDoubleQuotes(url.
fileName()));
1020 }
else if (!m_locationEdit->lineEdit()->text().isEmpty()) {
1021 m_locationEdit->clearEditText();
1024 if (m_operationMode == KFileWidget::Saving) {
1025 setNonExtSelection();
1034 relPath.remove(0, basePath.length());
1036 relPath.remove(0, 1);
1047 path.
replace(QStringLiteral(
"\\"), QStringLiteral(
"\\\\"));
1049 path.
replace(QStringLiteral(
"\""), QStringLiteral(
"\\\""));
1053void KFileWidgetPrivate::initDirOpWidgets()
1055 m_opsWidget =
new QWidget(q);
1056 m_opsWidgetLayout =
new QVBoxLayout(m_opsWidget);
1057 m_opsWidgetLayout->setContentsMargins(0, 0, 0, 0);
1058 m_opsWidgetLayout->setSpacing(0);
1060 m_model =
new KFilePlacesModel(q);
1068 m_urlNavigator =
new KUrlNavigator(m_model, QUrl(), m_opsWidget);
1069 m_urlNavigator->setPlacesSelectorVisible(
false);
1072 const auto navWidget =
new QWidget(m_opsWidget);
1073 const auto navLayout =
new QHBoxLayout(navWidget);
1074 navLayout->addWidget(m_urlNavigator);
1080 m_messageWidget =
new KMessageWidget(q);
1082 m_messageWidget->setWordWrap(
true);
1083 m_messageWidget->hide();
1085 auto topSeparator =
new QFrame(q);
1088 m_ops =
new KDirOperator(QUrl(), m_opsWidget);
1089 m_ops->installEventFilter(q);
1090 m_ops->setObjectName(QStringLiteral(
"KFileWidget::ops"));
1091 m_ops->setIsSaving(m_operationMode == KFileWidget::Saving);
1092 m_ops->setNewFileMenuSelectDirWhenAlreadyExist(
true);
1093 m_ops->showOpenWithActions(
true);
1096 auto bottomSparator =
new QFrame(q);
1099 q->connect(m_ops, &KDirOperator::urlEntered, q, [
this](
const QUrl &url) {
1103 fileHighlighted(item, isKeyNavigation);
1105 q->connect(m_ops, &KDirOperator::fileSelected, q, [
this](
const KFileItem &item) {
1108 q->connect(m_ops, &KDirOperator::finishedLoading, q, [
this]() {
1109 slotLoadingFinished();
1112 slotViewKeyEnterReturnPressed();
1116 q->setSelectedUrls(urls);
1123 m_ops->dirLister()->setAutoErrorHandlingEnabled(
false);
1125 m_messageWidget->setText(job->errorString());
1126 m_messageWidget->animatedShow();
1129 m_ops->setupMenu(KDirOperator::SortActions | KDirOperator::FileActions | KDirOperator::ViewActions);
1133 m_opsWidgetLayout->addWidget(m_toolbar);
1134 m_opsWidgetLayout->addWidget(navWidget);
1135 m_opsWidgetLayout->addWidget(m_messageWidget);
1136 m_opsWidgetLayout->addWidget(topSeparator);
1137 m_opsWidgetLayout->addWidget(m_ops);
1138 m_opsWidgetLayout->addWidget(bottomSparator);
1141void KFileWidgetPrivate::initZoomWidget()
1143 m_iconSizeSlider =
new QSlider(q);
1145 m_iconSizeSlider->setMinimumWidth(40);
1147 m_iconSizeSlider->setMinimum(0);
1148 m_iconSizeSlider->setMaximum(m_stdIconSizes.size() - 1);
1149 m_iconSizeSlider->setSingleStep(1);
1150 m_iconSizeSlider->setPageStep(1);
1154 slotIconSizeChanged(m_stdIconSizes[step]);
1158 slotIconSizeSliderMoved(m_stdIconSizes[step]);
1162 slotDirOpIconSizeChanged(iconSize);
1169 changeIconsSize(ZoomOut);
1173 q->addAction(m_zoomOutAction);
1179 changeIconsSize(ZoomIn);
1183 q->addAction(m_zoomInAction);
1186void KFileWidgetPrivate::initToolbar()
1188 m_toolbar =
new QToolBar(m_opsWidget);
1189 m_toolbar->setObjectName(QStringLiteral(
"KFileWidget::toolbar"));
1190 m_toolbar->setMovable(
false);
1201 ->setWhatsThis(
i18n(
"<qt>Click this button to enter the parent folder.<br /><br />"
1202 "For instance, if the current location is file:/home/konqi clicking this "
1203 "button will take you to file:/home.</qt>"));
1205 m_ops->action(
KDirOperator::Back)->setWhatsThis(
i18n(
"Click this button to move backwards one step in the browsing history."));
1206 m_ops->action(
KDirOperator::Forward)->setWhatsThis(
i18n(
"Click this button to move forward one step in the browsing history."));
1208 m_ops->action(
KDirOperator::Reload)->setWhatsThis(
i18n(
"Click this button to reload the contents of the current location."));
1212 m_togglePlacesPanelAction =
new KToggleAction(
i18n(
"Show Places Panel"), q);
1213 q->addAction(m_togglePlacesPanelAction);
1214 m_togglePlacesPanelAction->setShortcut(QKeySequence(
Qt::Key_F9));
1215 q->connect(m_togglePlacesPanelAction, &
QAction::toggled, q, [
this](
bool show) {
1216 togglePlacesPanel(show);
1219 m_toggleBookmarksAction =
new KToggleAction(
i18n(
"Show Bookmarks Button"), q);
1220 q->addAction(m_toggleBookmarksAction);
1221 q->connect(m_toggleBookmarksAction, &
QAction::toggled, q, [
this](
bool show) {
1222 toggleBookmarks(show);
1225 m_toggleQuickFilterAction =
new KToggleAction(
i18n(
"Show Quick Filter"), q);
1226 q->addAction(m_toggleQuickFilterAction);
1228 q->connect(m_toggleQuickFilterAction, &
QAction::toggled, q, [
this](
bool show) {
1229 setQuickFilterVisible(show);
1233 KActionMenu *menu =
new KActionMenu(
QIcon::fromTheme(QStringLiteral(
"configure")),
i18n(
"Options"), q);
1236 i18n(
"<qt>This is the preferences menu for the file dialog. "
1237 "Various options can be accessed from this menu including: <ul>"
1238 "<li>how files are sorted in the list</li>"
1239 "<li>types of view, including icon and list</li>"
1240 "<li>showing of hidden files</li>"
1241 "<li>the Places panel</li>"
1242 "<li>file previews</li>"
1243 "<li>separating folders from files</li></ul></qt>"));
1245 menu->
addAction(m_ops->action(KDirOperator::AllowExpansionInDetailsView));
1246 menu->addSeparator();
1248 menu->
addAction(m_togglePlacesPanelAction);
1249 menu->
addAction(m_toggleQuickFilterAction);
1250 menu->
addAction(m_toggleBookmarksAction);
1256 m_bookmarkButton =
new KActionMenu(
QIcon::fromTheme(QStringLiteral(
"bookmarks")),
i18n(
"Bookmarks"), q);
1258 q->addAction(m_bookmarkButton);
1259 m_bookmarkButton->setWhatsThis(
1260 i18n(
"<qt>This button allows you to bookmark specific locations. "
1261 "Click on this button to open the bookmark menu where you may add, "
1262 "edit or select a bookmark.<br /><br />"
1263 "These bookmarks are specific to the file dialog, but otherwise operate "
1264 "like bookmarks elsewhere in KDE.</qt>"));
1266 QWidget *midSpacer =
new QWidget(q);
1273 m_toolbar->addSeparator();
1274 m_toolbar->addAction(m_ops->action(KDirOperator::ViewIconsView));
1275 m_toolbar->addAction(m_ops->action(KDirOperator::ViewCompactView));
1276 m_toolbar->addAction(m_ops->action(KDirOperator::ViewDetailsView));
1277 m_toolbar->addSeparator();
1278 m_toolbar->addAction(m_ops->action(KDirOperator::ShowPreview));
1280 m_toolbar->addAction(m_bookmarkButton);
1282 m_toolbar->addWidget(midSpacer);
1285 m_toolbar->addAction(m_zoomOutAction);
1286 m_toolbar->addWidget(m_iconSizeSlider);
1287 m_toolbar->addAction(m_zoomInAction);
1288 m_toolbar->addSeparator();
1291 m_toolbar->addAction(menu);
1294 m_toolbar->setMovable(
false);
1297void KFileWidgetPrivate::initLocationWidget()
1299 m_locationLabel =
new QLabel(
i18n(
"&Name:"), q);
1300 m_locationEdit =
new KUrlComboBox(KUrlComboBox::Files,
true, q);
1301 m_locationEdit->installEventFilter(q);
1307 slotLocationChanged(text);
1311 m_locationEdit->lineEdit()->setClearButtonEnabled(
false);
1313 QAction *clearAction =
new QAction(
QIcon::fromTheme(QStringLiteral(
"edit-clear")), {}, m_locationEdit->lineEdit());
1318 clearAction->setVisible(m_locationEdit->lineEdit()->text().length() > 0);
1321 m_okButton->setEnabled(!text.isEmpty());
1324 QAction *undoAction =
new QAction(
QIcon::fromTheme(QStringLiteral(
"edit-undo")),
i18nc(
"@info:tooltip",
"Undo filename change"), m_locationEdit->lineEdit());
1329 undoAction->setVisible(m_locationEdit->lineEdit()->isUndoAvailable());
1332 updateLocationWhatsThis();
1333 m_locationLabel->setBuddy(m_locationEdit);
1335 KUrlCompletion *fileCompletionObj =
new KUrlCompletion(KUrlCompletion::FileCompletion);
1336 m_locationEdit->setCompletionObject(fileCompletionObj);
1337 m_locationEdit->setAutoDeleteCompletionObject(
true);
1340 locationAccepted(text);
1344void KFileWidgetPrivate::initFilterWidget()
1346 m_filterLabel =
new QLabel(q);
1347 m_filterWidget =
new KFileFilterCombo(q);
1354 m_filterLabel->setBuddy(m_filterWidget);
1356 slotMimeFilterChanged();
1359 m_filterDelayTimer.setSingleShot(
true);
1360 m_filterDelayTimer.setInterval(300);
1363 slotMimeFilterChanged();
1367void KFileWidgetPrivate::initQuickFilterWidget()
1369 m_quickFilter =
new QWidget(q);
1371 m_quickFilterLock =
new QToolButton(m_quickFilter);
1372 m_quickFilterLock->setAutoRaise(
true);
1373 m_quickFilterLock->setCheckable(
true);
1374 m_quickFilterLock->setIcon(
QIcon::fromTheme(QStringLiteral(
"object-unlocked")));
1375 m_quickFilterLock->setToolTip(
i18nc(
"@info:tooltip",
"Keep Filter When Changing Folders"));
1377 m_quickFilterEdit =
new QLineEdit(m_quickFilter);
1378 m_quickFilterEdit->setClearButtonEnabled(
true);
1379 m_quickFilterEdit->setPlaceholderText(
i18n(
"Filter by name…"));
1381 slotQuickFilterChanged();
1384 m_quickFilterClose =
new QToolButton(m_quickFilter);
1385 m_quickFilterClose->setAutoRaise(
true);
1386 m_quickFilterClose->setIcon(
QIcon::fromTheme(QStringLiteral(
"dialog-close")));
1387 m_quickFilterClose->setToolTip(
i18nc(
"@info:tooltip",
"Hide Filter Bar"));
1389 setQuickFilterVisible(
false);
1392 QHBoxLayout *hLayout =
new QHBoxLayout(m_quickFilter);
1393 hLayout->setContentsMargins(0, 0, 0, 0);
1394 hLayout->addWidget(m_quickFilterLock);
1395 hLayout->addWidget(m_quickFilterEdit);
1396 hLayout->addWidget(m_quickFilterClose);
1399 m_quickFilter->hide();
1402void KFileWidgetPrivate::setLocationText(
const QList<QUrl> &urlList)
1407 const QSignalBlocker blocker(m_locationEdit);
1409 const QUrl baseUrl = m_ops->
url();
1411 if (urlList.
count() > 1) {
1413 for (
const QUrl &url : urlList) {
1414 urls += QStringLiteral(
"\"%1\" ").
arg(escapeDoubleQuotes(relativePathOrUrl(baseUrl, url)));
1418 m_locationEdit->lineEdit()->selectAll();
1419 m_locationEdit->lineEdit()->insert(urls);
1420 }
else if (urlList.count() == 1) {
1421 const auto url = urlList[0];
1422 m_locationEdit->lineEdit()->selectAll();
1423 m_locationEdit->lineEdit()->insert(escapeDoubleQuotes(relativePathOrUrl(baseUrl, url)));
1424 }
else if (!m_locationEdit->lineEdit()->text().isEmpty()) {
1425 m_locationEdit->clearEditText();
1428 if (m_operationMode == KFileWidget::Saving) {
1429 setNonExtSelection();
1433void KFileWidgetPrivate::updateLocationWhatsThis()
1435 const QString autocompletionWhatsThisText =
i18n(
1436 "<qt>While typing in the text area, you may be presented "
1437 "with possible matches. "
1438 "This feature can be controlled by clicking with the right mouse button "
1439 "and selecting a preferred mode from the <b>Text Completion</b> menu.</qt>");
1441 QString whatsThisText;
1442 if (m_operationMode == KFileWidget::Saving) {
1443 whatsThisText = QLatin1String(
"<qt>") +
i18n(
"This is the name to save the file as.") + autocompletionWhatsThisText;
1444 }
else if (m_ops->mode() & KFile::Files) {
1445 whatsThisText = QLatin1String(
"<qt>")
1446 +
i18n(
"This is the list of files to open. More than "
1447 "one file can be specified by listing several "
1448 "files, separated by spaces.")
1449 + autocompletionWhatsThisText;
1451 whatsThisText = QLatin1String(
"<qt>") +
i18n(
"This is the name of the file to open.") + autocompletionWhatsThisText;
1454 m_locationLabel->setWhatsThis(whatsThisText);
1455 m_locationEdit->setWhatsThis(whatsThisText);
1458void KFileWidgetPrivate::initPlacesPanel()
1464 m_placesDock =
new QDockWidget(
i18nc(
"@title:window",
"Places"), q);
1466 m_placesDock->setTitleBarWidget(
new KDEPrivate::KFileWidgetDockTitleBar(m_placesDock));
1468 m_placesView =
new KFilePlacesView(m_placesDock);
1469 m_placesView->setModel(m_model);
1472 m_placesView->setObjectName(QStringLiteral(
"url bar"));
1473 QObject::connect(m_placesView, &KFilePlacesView::urlChanged, q, [
this](
const QUrl &url) {
1478 m_messageWidget->setText(errorMessage);
1479 m_messageWidget->animatedShow();
1486 m_placesView->setUrl(m_url);
1488 m_placesDock->setWidget(m_placesView);
1489 m_placesViewSplitter->insertWidget(0, m_placesDock);
1492 m_placesViewWidth = m_configGroup.readEntry(SpeedbarWidth, m_placesView->sizeHint().width());
1495 setPlacesViewSplitterSizes();
1498 togglePlacesPanel(visible, m_placesDock);
1502void KFileWidgetPrivate::setPlacesViewSplitterSizes()
1504 if (m_placesViewWidth > 0) {
1505 QList<int> sizes = m_placesViewSplitter->sizes();
1506 sizes[0] = m_placesViewWidth;
1507 sizes[1] = q->width() - m_placesViewWidth - m_placesViewSplitter->handleWidth();
1508 m_placesViewSplitter->setSizes(sizes);
1512void KFileWidgetPrivate::initGUI()
1516 m_boxLayout =
new QVBoxLayout(q);
1517 m_boxLayout->setContentsMargins(0, 0, 0, 0);
1519 m_placesViewSplitter =
new QSplitter(q);
1521 m_placesViewSplitter->setChildrenCollapsible(
false);
1522 m_boxLayout->addWidget(m_placesViewSplitter);
1525 placesViewSplitterMoved(pos, index);
1527 m_placesViewSplitter->insertWidget(0, m_opsWidget);
1529 m_lafBox =
new QFormLayout();
1536 m_lafBox->addRow(m_quickFilter);
1537 m_lafBox->addRow(m_locationLabel, m_locationEdit);
1538 m_lafBox->addRow(m_filterLabel, m_filterWidget);
1540 m_lafBox->addWidget(m_autoSelectExtCheckBox);
1542 m_opsWidgetLayout->addLayout(m_lafBox);
1544 auto hbox =
new QHBoxLayout();
1551 hbox->addStretch(2);
1552 hbox->addWidget(m_okButton);
1553 hbox->addWidget(m_cancelButton);
1555 m_opsWidgetLayout->addLayout(hbox);
1557 auto updateTabOrder = [
this]() {
1559 q->setTabOrder(m_urlNavigator, m_ops);
1561 q->setTabOrder(m_ops, m_autoSelectExtCheckBox);
1562 q->setTabOrder(m_autoSelectExtCheckBox, m_quickFilterLock);
1563 q->setTabOrder(m_quickFilterLock, m_quickFilterEdit);
1564 q->setTabOrder(m_quickFilterEdit, m_quickFilterClose);
1565 q->setTabOrder(m_quickFilterClose, m_locationEdit);
1566 q->setTabOrder(m_locationEdit, m_filterWidget);
1567 q->setTabOrder(m_filterWidget, m_okButton);
1568 q->setTabOrder(m_okButton, m_cancelButton);
1569 q->setTabOrder(m_cancelButton, m_placesView);
1572 const auto toolbarChildren = m_toolbar->children();
1573 QList<QWidget *> toolbarButtons;
1574 for (QObject *obj : std::as_const(toolbarChildren)) {
1575 if (
auto *button = qobject_cast<QToolButton *>(obj)) {
1578 toolbarButtons << button;
1579 }
else if (
auto *slider = qobject_cast<QSlider *>(obj)) {
1580 toolbarButtons << slider;
1584 q->setTabOrder(m_placesView, toolbarButtons.
first());
1588 while (nextIt != toolbarButtons.
constEnd()) {
1589 q->setTabOrder(*it, *nextIt);
1599void KFileWidgetPrivate::slotMimeFilterChanged()
1601 m_filterDelayTimer.stop();
1603 KFileFilter
filter = m_filterWidget->currentFilter();
1605 m_ops->clearFilter();
1607 if (!
filter.mimePatterns().isEmpty()) {
1608 QStringList types =
filter.mimePatterns();
1609 types.
prepend(QStringLiteral(
"inode/directory"));
1610 m_ops->setMimeFilter(types);
1613 updateNameFilter(filter);
1615 updateAutoSelectExtension();
1619 Q_EMIT q->filterChanged(filter);
1622void KFileWidgetPrivate::slotQuickFilterChanged()
1624 m_filterDelayTimer.stop();
1626 KFileFilter
filter(QStringLiteral(
"quickFilter"), QStringList{m_quickFilterEdit->text()}, m_filterWidget->currentFilter().mimePatterns());
1627 m_ops->clearFilter();
1628 m_ops->setMimeFilter(
filter.mimePatterns());
1630 updateNameFilter(filter);
1634 Q_EMIT q->filterChanged(filter);
1637void KFileWidgetPrivate::updateNameFilter(
const KFileFilter &filter)
1639 const auto filePatterns =
filter.filePatterns();
1640 const bool hasRegExSyntax = std::any_of(filePatterns.constBegin(), filePatterns.constEnd(), [](
const QString &filter) {
1642 return filter.contains(QLatin1Char(
'*')) || filter.contains(QLatin1Char(
'?')) || filter.contains(QLatin1Char(
'['));
1645 if (hasRegExSyntax) {
1646 m_ops->setNameFilter(
filter.filePatterns().join(QLatin1Char(
' ')));
1648 m_ops->setNameFilter(QLatin1Char(
'*') + filePatterns.join(QLatin1Char(
'*')) + QLatin1Char(
'*'));
1656 d->m_ops->setUrl(url, clearforward);
1660void KFileWidgetPrivate::urlEntered(
const QUrl &url)
1665 if (pathCombo->
count() != 0) {
1670 if (m_keepLocation) {
1671 const QUrl currentUrl = urlFromString(locationEditCurrentText());
1675 m_locationEdit->lineEdit()->setModified(
true);
1678 m_locationEdit->blockSignals(blocked);
1680 m_urlNavigator->setLocationUrl(url);
1683 KUrlCompletion *
completion =
dynamic_cast<KUrlCompletion *
>(m_locationEdit->completionObject());
1689 m_placesView->setUrl(url);
1692 m_messageWidget->hide();
1695void KFileWidgetPrivate::locationAccepted(
const QString &url)
1702void KFileWidgetPrivate::enterUrl(
const QUrl &url)
1709 Utils::appendSlashToPath(u);
1716 if (q->window()->focusWidget() != m_locationEdit) {
1721 if (!m_quickFilterLock->isChecked()) {
1722 setQuickFilterVisible(
false);
1726void KFileWidgetPrivate::enterUrl(
const QString &url)
1733bool KFileWidgetPrivate::toOverwrite(
const QUrl &url)
1739 bool res = statJob->
exec();
1743 i18n(
"The file \"%1\" already exists. Do you wish to overwrite it?", url.
fileName()),
1744 i18n(
"Overwrite File?"),
1751 m_locationEdit->setFocus();
1752 setNonExtSelection();
1768 d->setLocationText(url);
1781 d->setLocationText(urls);
1784void KFileWidgetPrivate::slotLoadingFinished()
1791 m_ops->blockSignals(
true);
1792 QUrl u(m_ops->url());
1793 if (currentText.
startsWith(QLatin1Char(
'/'))) {
1796 u.
setPath(Utils::concatPaths(m_ops->url().path(), currentText));
1798 m_ops->setCurrentItem(u);
1799 m_ops->blockSignals(
false);
1802void KFileWidgetPrivate::slotLocationChanged(
const QString &text)
1806 m_locationEdit->lineEdit()->setModified(
true);
1808 if (text.
isEmpty() && m_ops->view()) {
1809 m_ops->view()->clearSelection();
1812 if (!m_locationEdit->lineEdit()->text().isEmpty()) {
1813 const QList<QUrl> urlList(tokenize(text));
1814 m_ops->setCurrentItems(urlList);
1824 if (d->m_inAccept) {
1836 if (d->m_inAccept) {
1837 if (d->m_ops->mode() & KFile::Files) {
1838 list = d->m_urlList;
1848 qCDebug(KIO_KFILEWIDGETS_FW) <<
"Tokenizing:" << line;
1852 Utils::appendSlashToPath(baseUrl);
1856 auto addUrl = [baseUrl, &urls](
const QString &partial_name) {
1857 if (partial_name.trimmed().isEmpty()) {
1862 QUrl partial_url(partial_name);
1863 if (!partial_url.isValid()
1864 || partial_url.isRelative()
1866 || (!partial_url.scheme().isEmpty() && (!partial_name.contains(QStringLiteral(
"://")) || !
KProtocolInfo::isKnownProtocol(partial_url.scheme())))) {
1869 partial_url.clear();
1870 partial_url.setPath(partial_name);
1875 if (partial_url.isRelative() || baseUrl.
isParentOf(partial_url)) {
1876 partial_url = baseUrl.
resolved(partial_url);
1879 if (partial_url.isValid()) {
1880 urls.
append(partial_url);
1883 qCDebug(KIO_KFILEWIDGETS_FW) <<
"Discarding Invalid" << partial_url;
1890 QString partial_name;
1891 bool escape =
false;
1892 for (
int i = 0; i < line.
length(); i++) {
1893 const QChar ch = line[i];
1911 if (ch.
toLatin1() ==
'"' && q->mode() != KFile::Mode::File) {
1912 addUrl(partial_name);
1913 partial_name.
clear();
1924 if (!partial_name.
isEmpty()) {
1925 addUrl(partial_name);
1926 partial_name.
clear();
1936 if (d->m_inAccept) {
1937 const QUrl url = d->mostLocalUrl(d->m_url);
1953 if (d->m_inAccept) {
1954 if (d->m_ops->mode() & KFile::Files) {
1956 for (
const auto &u : urls) {
1957 const QUrl url = d->mostLocalUrl(u);
1965 if (d->m_url.isLocalFile()) {
1966 list.
append(d->m_url.toLocalFile());
1976 return d->m_ops->
url();
1983 if (d->m_placesDock) {
1986 d->setPlacesViewSplitterSizes();
1990void KFileWidget::showEvent(
QShowEvent *event)
1992 if (!d->m_hasView) {
1995 d->m_ops->setViewMode(KFile::Default);
1996 d->m_hasView =
true;
1999 d->slotViewDoubleClicked(index);
2002 d->m_ops->clearHistory();
2007bool KFileWidget::eventFilter(
QObject *watched,
QEvent *event)
2016 const auto type =
event->type();
2033 d->m_ops->setMode(m);
2034 if (d->m_ops->dirOnlyMode()) {
2035 d->m_filterWidget->setDefaultFilter(
KFileFilter(
i18n(
"All Folders"), {QStringLiteral(
"*")}, {}));
2037 d->m_filterWidget->setDefaultFilter(
KFileFilter(
i18n(
"All Files"), {QStringLiteral(
"*")}, {}));
2040 d->updateAutoSelectExtension();
2045 return d->m_ops->mode();
2048void KFileWidgetPrivate::readViewConfig()
2062 m_locationEdit->setCompletionMode(cm);
2066 togglePlacesPanel(m_configGroup.readEntry(ShowSpeedbar,
true));
2069 toggleBookmarks(m_configGroup.readEntry(ShowBookmarks,
false));
2072 m_autoSelectExtChecked = m_configGroup.readEntry(AutoSelectExtChecked, DefaultAutoSelectExtChecked);
2073 updateAutoSelectExtension();
2076 m_urlNavigator->setUrlEditable(!m_configGroup.readEntry(BreadcrumbNavigation,
true));
2079 m_urlNavigator->setShowFullPath(m_configGroup.readEntry(ShowFullPath,
false));
2081 int w1 = q->minimumSize().width();
2082 int w2 = m_toolbar->sizeHint().width();
2084 q->setMinimumWidth(w2);
2088void KFileWidgetPrivate::writeViewConfig()
2096 KConfigGroup tmpGroup(&tmp, ConfigGroup);
2098 KUrlComboBox *pathCombo = m_urlNavigator->editor();
2100 tmpGroup.writeEntry(PathComboCompletionMode,
static_cast<int>(pathCombo->
completionMode()));
2101 tmpGroup.writeEntry(LocationComboCompletionMode,
static_cast<int>(m_locationEdit->completionMode()));
2103 const bool showPlacesPanel = m_placesDock && !m_placesDock->
isHidden();
2104 tmpGroup.writeEntry(ShowSpeedbar, showPlacesPanel);
2105 if (m_placesViewWidth > 0) {
2106 tmpGroup.writeEntry(SpeedbarWidth, m_placesViewWidth);
2109 tmpGroup.writeEntry(ShowBookmarks, m_bookmarkHandler !=
nullptr);
2110 tmpGroup.writeEntry(AutoSelectExtChecked, m_autoSelectExtChecked);
2111 tmpGroup.writeEntry(BreadcrumbNavigation, !m_urlNavigator->isUrlEditable());
2112 tmpGroup.writeEntry(ShowFullPath, m_urlNavigator->showFullPath());
2114 m_ops->writeConfig(tmpGroup);
2120void KFileWidgetPrivate::readRecentFiles()
2124 const bool oldState = m_locationEdit->blockSignals(
true);
2125 m_locationEdit->setMaxItems(m_configGroup.readEntry(RecentFilesNumber, DefaultRecentURLsNumber));
2126 m_locationEdit->setUrls(m_stateConfigGroup.readPathEntry(RecentFiles, QStringList()), KUrlComboBox::RemoveBottom);
2127 m_locationEdit->setCurrentIndex(-1);
2128 m_locationEdit->blockSignals(oldState);
2130 KUrlComboBox *combo = m_urlNavigator->editor();
2131 combo->
setUrls(m_stateConfigGroup.readPathEntry(RecentURLs, QStringList()), KUrlComboBox::RemoveTop);
2132 combo->
setMaxItems(m_configGroup.readEntry(RecentURLsNumber, DefaultRecentURLsNumber));
2133 combo->
setUrl(m_ops->url());
2136 KUrlCompletion *
completion =
dynamic_cast<KUrlCompletion *
>(m_locationEdit->completionObject());
2142void KFileWidgetPrivate::saveRecentFiles()
2145 m_stateConfigGroup.writePathEntry(RecentFiles, m_locationEdit->urls());
2147 KUrlComboBox *pathCombo = m_urlNavigator->editor();
2148 m_stateConfigGroup.writePathEntry(RecentURLs, pathCombo->urls());
2153 return d->m_okButton;
2158 return d->m_cancelButton;
2162void KFileWidget::slotCancel()
2164 d->writeViewConfig();
2170 d->m_keepLocation = keep;
2175 return d->m_keepLocation;
2182 d->m_operationMode =
mode;
2183 d->m_keepLocation = (
mode == Saving);
2184 d->m_filterWidget->setEditable(!d->m_hasDefaultFilter ||
mode != Saving);
2185 if (
mode == Opening) {
2187 d->m_okButton->setText(
i18n(
"&Open"));
2192 }
else if (
mode == Saving) {
2194 d->setNonExtSelection();
2198 d->updateLocationWhatsThis();
2199 d->updateAutoSelectExtension();
2202 d->m_ops->setIsSaving(
mode == Saving);
2204 d->updateFilterText();
2209 return d->m_operationMode;
2212void KFileWidgetPrivate::slotAutoSelectExtClicked()
2218 m_autoSelectExtChecked = m_autoSelectExtCheckBox->
isChecked();
2221 updateLocationEditExtension(m_extension );
2224void KFileWidgetPrivate::placesViewSplitterMoved(
int pos,
int index)
2230 if (m_placesDock && index == 1) {
2231 m_placesViewWidth = pos;
2236void KFileWidgetPrivate::activateUrlNavigator()
2240 QLineEdit *lineEdit = m_urlNavigator->editor()->lineEdit();
2245 m_urlNavigator->setUrlEditable(
false);
2247 m_urlNavigator->setUrlEditable(
true);
2248 m_urlNavigator->setFocus();
2253void KFileWidgetPrivate::slotDirOpIconSizeChanged(
int size)
2255 auto beginIt = m_stdIconSizes.cbegin();
2256 auto endIt = m_stdIconSizes.cend();
2257 auto it = std::lower_bound(beginIt, endIt, size);
2258 const int sliderStep = it != endIt ? it - beginIt : 0;
2259 m_iconSizeSlider->setValue(sliderStep);
2260 m_zoomOutAction->setDisabled(it == beginIt);
2261 m_zoomInAction->setDisabled(it == (endIt - 1));
2264void KFileWidgetPrivate::changeIconsSize(ZoomState zoom)
2266 int step = m_iconSizeSlider->value();
2268 if (zoom == ZoomOut) {
2274 if (step ==
static_cast<int>(m_stdIconSizes.size() - 1)) {
2280 m_iconSizeSlider->setValue(step);
2281 slotIconSizeSliderMoved(m_stdIconSizes[step]);
2284void KFileWidgetPrivate::slotIconSizeChanged(
int _value)
2286 m_ops->setIconSize(_value);
2287 m_iconSizeSlider->setToolTip(
i18n(
"Icon size: %1 pixels", _value));
2290void KFileWidgetPrivate::slotIconSizeSliderMoved(
int size)
2294 slotIconSizeChanged(size);
2296 QPoint global(m_iconSizeSlider->rect().topLeft());
2297 global.ry() += m_iconSizeSlider->height() / 2;
2298 QHelpEvent toolTipEvent(
QEvent::ToolTip, QPoint(0, 0), m_iconSizeSlider->mapToGlobal(global));
2302void KFileWidgetPrivate::slotViewDoubleClicked(
const QModelIndex &index)
2305 if (m_operationMode == KFileWidget::Saving && index.
isValid() && m_ops->selectedItems().constFirst().isFile()) {
2310void KFileWidgetPrivate::slotViewKeyEnterReturnPressed()
2314 if (m_operationMode == KFileWidget::Saving && (m_ops->mode() & KFile::File) && m_ops->selectedItems().isEmpty()) {
2363void KFileWidgetPrivate::updateAutoSelectExtension()
2365 if (!m_autoSelectExtCheckBox) {
2378 QString lastExtension = m_extension;
2379 m_extension.
clear();
2382 if ((m_operationMode == KFileWidget::Saving) && (m_ops->mode() & KFile::File)) {
2387 KFileFilter fileFilter = m_filterWidget->currentFilter();
2393 if (currentExtension.
isEmpty()) {
2394 currentExtension = locationEditCurrentText().
section(QLatin1Char(
'.'), -1, -1);
2398 QString defaultExtension;
2399 QStringList extensionList;
2404 defaultExtension = getExtensionFromPatternList(extensionList);
2412 if (!defaultExtension.
isEmpty()) {
2413 defaultExtension.
prepend(QLatin1Char(
'.'));
2418 if ((!currentExtension.
isEmpty() && extensionList.
contains(QLatin1String(
"*.") + currentExtension))) {
2419 m_extension = QLatin1Char(
'.') + currentExtension;
2421 m_extension = defaultExtension;
2431 QString whatsThisExtension;
2432 if (!m_extension.isEmpty()) {
2434 m_autoSelectExtCheckBox->setText(
i18n(
"Automatically select filename e&xtension (%1)", m_extension));
2435 whatsThisExtension =
i18n(
"the extension <b>%1</b>", m_extension);
2437 m_autoSelectExtCheckBox->setEnabled(
true);
2438 m_autoSelectExtCheckBox->setChecked(m_autoSelectExtChecked);
2441 m_autoSelectExtCheckBox->setText(
i18n(
"Automatically select filename e&xtension"));
2442 whatsThisExtension =
i18n(
"a suitable extension");
2444 m_autoSelectExtCheckBox->setChecked(
false);
2445 m_autoSelectExtCheckBox->setEnabled(
false);
2448 const QString locationLabelText = stripUndisplayable(m_locationLabel->text());
2449 m_autoSelectExtCheckBox->setWhatsThis(QLatin1String(
"<qt>")
2450 +
i18n(
"This option enables some convenient features for "
2451 "saving files with extensions:<br />"
2453 "<li>Any extension specified in the <b>%1</b> text "
2454 "area will be updated if you change the file type "
2457 "<li>If no extension is specified in the <b>%2</b> "
2458 "text area when you click "
2459 "<b>Save</b>, %3 will be added to the end of the "
2460 "filename (if the filename does not already exist). "
2461 "This extension is based on the file type that you "
2462 "have chosen to save in.<br />"
2464 "If you do not want KDE to supply an extension for the "
2465 "filename, you can either turn this option off or you "
2466 "can suppress it by adding a period (.) to the end of "
2467 "the filename (the period will be automatically "
2471 "If unsure, keep this option enabled as it makes your "
2472 "files more manageable.",
2476 + QLatin1String(
"</qt>"));
2478 m_autoSelectExtCheckBox->show();
2481 updateLocationEditExtension(lastExtension);
2485 m_autoSelectExtCheckBox->setChecked(
false);
2486 m_autoSelectExtCheckBox->hide();
2493void KFileWidgetPrivate::updateLocationEditExtension(
const QString &lastExtension)
2495 if (!m_autoSelectExtCheckBox->isChecked() || m_extension.isEmpty()) {
2499 const QString urlStr = locationEditCurrentText();
2504 const int fileNameOffset = urlStr.
lastIndexOf(QLatin1Char(
'/')) + 1;
2505 QStringView fileName = QStringView(urlStr).mid(fileNameOffset);
2507 const int dot = fileName.
lastIndexOf(QLatin1Char(
'.'));
2508 const int len = fileName.
length();
2513 const QUrl url = getCompleteUrl(urlStr);
2518 bool result = statJob->
exec();
2537 }
else if (!m_extension.isEmpty() && fileName.
endsWith(m_extension)) {
2538 fileName.
chop(m_extension.length());
2544 const QString newText = QStringView(urlStr).left(fileNameOffset) + fileName + m_extension;
2545 if (newText != locationEditCurrentText()) {
2546 const int idx = m_locationEdit->currentIndex();
2548 m_locationEdit->lineEdit()->selectAll();
2549 m_locationEdit->lineEdit()->insert(newText);
2551 m_locationEdit->setItemText(idx, newText);
2553 m_locationEdit->lineEdit()->setModified(
true);
2563 QRegularExpression rx;
2564 for (
const QString &p : patterns) {
2575void KFileWidgetPrivate::updateFilter()
2577 if ((m_operationMode == KFileWidget::Saving) && (m_ops->mode() & KFile::File)) {
2578 QString urlStr = locationEditCurrentText();
2586 bool matchesCurrentFilter = [
this, urlMimeType, urlStr] {
2587 const KFileFilter
filter = m_filterWidget->currentFilter();
2588 if (
filter.mimePatterns().contains(urlMimeType.
name())) {
2592 QString filename = urlStr.
mid(urlStr.
lastIndexOf(QLatin1Char(
'/')) + 1);
2594 const auto filePatterns =
filter.filePatterns();
2595 const bool hasMatch = std::any_of(filePatterns.cbegin(), filePatterns.cend(), [filename](
const QString &pattern) {
2596 QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(pattern));
2598 return rx.match(filename).hasMatch();
2603 if (matchesCurrentFilter) {
2607 const auto filters = m_filterWidget->filters();
2609 auto filterIt = std::find_if(filters.cbegin(), filters.cend(), [urlStr, urlMimeType](
const KFileFilter &filter) {
2610 if (filter.mimePatterns().contains(urlMimeType.name())) {
2614 QString filename = urlStr.
mid(urlStr.
lastIndexOf(QLatin1Char(
'/')) + 1);
2617 const auto filePatterns =
filter.filePatterns();
2618 const bool hasMatch = std::any_of(filePatterns.cbegin(), filePatterns.cend(), [filename](
const QString &pattern) {
2620 if (pattern == QLatin1String(
"*")) {
2626 return rx.
match(filename).hasMatch();
2632 if (filterIt != filters.cend()) {
2633 m_filterWidget->setCurrentFilter(*filterIt);
2639void KFileWidgetPrivate::appendExtension(
QUrl &url)
2643 if (!m_autoSelectExtCheckBox->isChecked() || m_extension.isEmpty()) {
2654 const int len = fileName.
length();
2655 const int dot = fileName.
lastIndexOf(QLatin1Char(
'.'));
2657 const bool suppressExtension = (dot == len - 1);
2658 const bool unspecifiedExtension = !fileName.
endsWith(m_extension);
2661 if (!(suppressExtension || unspecifiedExtension)) {
2668 bool res = statJob->
exec();
2675 if (suppressExtension) {
2692 else if (unspecifiedExtension) {
2701void KFileWidgetPrivate::addToRecentDocuments()
2703 int m = m_ops->mode();
2707 if (m & KFile::LocalOnly) {
2708 const QStringList files = q->selectedFiles();
2710 for (; it != files.
end() && atmost > 0; ++it) {
2717 const QList<QUrl> urls = q->selectedUrls();
2719 for (; it != urls.
end() && atmost > 0; ++it) {
2720 if ((*it).isValid()) {
2730 return d->m_locationEdit;
2735 return d->m_filterWidget;
2738void KFileWidgetPrivate::togglePlacesPanel(
bool show,
QObject *sender)
2742 m_placesDock->
show();
2748 for (
int rowIndex = 0; rowIndex < model->
rowCount(); rowIndex++) {
2758 if (sender == m_placesDock && m_placesDock && m_placesDock->isVisibleTo(q)) {
2765 m_placesDock->hide();
2770 if (!m_toolbar->actions().contains(homeAction)) {
2771 m_toolbar->insertAction(reloadAction, homeAction);
2775 m_togglePlacesPanelAction->setChecked(show);
2778 m_urlNavigator->setPlacesSelectorVisible(!show);
2781void KFileWidgetPrivate::toggleBookmarks(
bool show)
2784 if (m_bookmarkHandler) {
2787 m_bookmarkHandler =
new KFileBookmarkHandler(q);
2788 q->connect(m_bookmarkHandler, &KFileBookmarkHandler::openUrl, q, [
this](
const QString &path) {
2791 m_bookmarkButton->setMenu(m_bookmarkHandler->menu());
2792 }
else if (m_bookmarkHandler) {
2793 m_bookmarkButton->setMenu(
nullptr);
2794 delete m_bookmarkHandler;
2795 m_bookmarkHandler =
nullptr;
2798 if (m_bookmarkButton) {
2799 m_bookmarkButton->setVisible(show);
2802 m_toggleBookmarksAction->setChecked(show);
2805void KFileWidgetPrivate::setQuickFilterVisible(
bool show)
2807 if (m_quickFilter->isVisible() == show) {
2811 m_filterWidget->setEnabled(!show);
2813 m_quickFilterEdit->setFocus();
2815 m_quickFilterEdit->clear();
2817 m_quickFilterLock->setChecked(
false);
2818 m_ops->dirLister()->setQuickFilterMode(show);
2819 m_toggleQuickFilterAction->setChecked(show);
2826 return getStartUrl(startDir, recentDirClass, fileName);
2832 recentDirClass.
clear();
2836 bool useDefaultStartDir = startDir.
isEmpty();
2837 if (!useDefaultStartDir) {
2855 keyword = urlDir.
mid(1);
2860 recentDirClass = query.arg(keyword);
2876 useDefaultStartDir =
true;
2881 useDefaultStartDir =
true;
2886 if (useDefaultStartDir) {
2887 if (lastDirectory()->isEmpty()) {
2896 || !
QDir(lastDirectory()->toLocalFile()).exists()) {
2900 ret = *lastDirectory();
2910 *lastDirectory() = directory;
2914void KFileWidgetPrivate::setNonExtSelection()
2917 QString filename = locationEditCurrentText();
2924 int lastDot = filename.
lastIndexOf(QLatin1Char(
'.'));
2926 m_locationEdit->lineEdit()->setSelection(0, lastDot);
2928 m_locationEdit->lineEdit()->selectAll();
2935void KFileWidgetPrivate::updateFilterText()
2938 QString whatsThisText;
2940 if (m_operationMode == KFileWidget::Saving && !m_filterWidget->currentFilter().mimePatterns().isEmpty()) {
2941 whatsThisText =
i18n(
"<qt>This is the file type selector. It is used to select the format that the file will be saved as.</qt>");
2943 whatsThisText =
i18n(
"<qt>This is the file type selector. It is used to select the format of the files shown.</qt>");
2946 if (m_filterLabel) {
2947 m_filterLabel->setText(label);
2948 m_filterLabel->setWhatsThis(whatsThisText);
2950 if (m_filterWidget) {
2951 m_filterWidget->setWhatsThis(whatsThisText);
2957 delete d->m_bottomCustomWidget;
2958 d->m_bottomCustomWidget = widget;
2963 d->m_bottomCustomWidget->
setParent(
this);
2965 d->m_opsWidgetLayout->addWidget(d->m_bottomCustomWidget);
2972 setTabOrder(d->m_cancelButton, d->m_bottomCustomWidget);
2973 setTabOrder(d->m_bottomCustomWidget, d->m_urlNavigator);
2978 delete d->m_labeledCustomWidget;
2979 d->m_labeledCustomWidget = widget;
2983 d->m_lafBox->addRow(label, widget);
2991#if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(6, 3)
2994 d->m_configGroup = group;
2995 d->readViewConfig();
2996 d->readRecentFiles();
3000QString KFileWidgetPrivate::locationEditCurrentText()
const
3005QUrl KFileWidgetPrivate::mostLocalUrl(
const QUrl &url)
3013 bool res = statJob->
exec();
3029void KFileWidgetPrivate::setInlinePreviewShown(
bool show)
3031 m_ops->setInlinePreviewShown(show);
3036 d->m_confirmOverwrite = enable;
3041 d->setInlinePreviewShown(
show);
3047 QSize goodSize(48 * fontSize, 30 * fontSize);
3048 const QSize scrnSize = d->screenSize();
3049 QSize minSize(scrnSize / 2);
3050 QSize maxSize(scrnSize * qreal(0.9));
3056 d->m_ops->setViewMode(
mode);
3057 d->m_hasView =
true;
3062 d->m_model->setSupportedSchemes(schemes);
3063 d->m_ops->setSupportedSchemes(schemes);
3064 d->m_urlNavigator->setSupportedSchemes(schemes);
3069 return d->m_model->supportedSchemes();
3072#include "moc_kfilewidget.cpp"
void returnPressed(const QString &text)
virtual void setCompletionMode(KCompletion::CompletionMode mode)
void setAutoDeleteCompletionObject(bool autoDelete)
KCompletion::CompletionMode completionMode() const
QString readEntry(const char *key, const char *aDefault=nullptr) const
void jobError(KIO::Job *job)
Emitted if listing a directory fails with an error.
This widget works as a network transparent filebrowser.
void keyEnterReturnPressed()
Triggered when the user hit Enter/Return.
void renamingFinished(const QList< QUrl > &urls)
Emitted when renaming selected files has finished.
void updateSelectionDependentActions()
Enables/disables actions that are selection dependent.
virtual void readConfig(const KConfigGroup &configGroup)
Reads the default settings for a view, i.e. the default KFile::FileView.
void fileHighlighted(const KFileItem &item, bool isKeyNavigation)
Emitted when a file is highlighted or generally the selection changes in multiselection mode.
@ Up
Changes to the parent directory.
@ Home
Changes to the user's home directory.
@ ShowHiddenFiles
shows hidden files
@ ShowPreviewPanel
shows a preview next to the fileview
@ Forward
Goes forward in the history.
@ NewFolder
Opens a dialog box to create a directory.
@ SortMenu
An ActionMenu containing all sort-options.
@ SortHiddenFilesLast
Sorts hidden files last.
@ Reload
Reloads the current directory.
@ Back
Goes back to the previous directory.
void viewChanged(QAbstractItemView *newView)
Emitted whenever the current fileview is changed, either by an explicit call to setView() or by the u...
QAction * action(KDirOperator::Action action) const
Obtain a given action from the KDirOperator's set of actions.
void currentIconSizeChanged(int size)
Will notify that the icon size has changed.
virtual void setViewConfig(KConfigGroup &configGroup)
Sets the config object and the to be used group in KDirOperator.
void filterChanged()
This signal is emitted whenever the filter has been changed.
Encapsulates rules to filter a list of files.
QStringList filePatterns() const
List of file name patterns that are included by this filter.
bool isEmpty() const
Whether the filer is empty, i.e. matches all files.
QStringList mimePatterns() const
List of MIME types that are included by this filter;.
A KFileItem is a generic class to handle a file, local or remote.
bool isNull() const
Return true if default-constructed.
This class is a list view model.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Get the children model index for the given row and column.
Q_INVOKABLE QUrl url(const QModelIndex &index) const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Get the number of rows for a model index.
void errorMessage(const QString &message)
message An error message explaining what went wrong.
QFlags< Mode > Modes
Stores a combination of Mode values.
static void assign(QPushButton *button, const KGuiItem &item)
A KIO job that retrieves information about a file or directory.
const UDSEntry & statResult() const
Result of the stat operation.
QString stringValue(uint field) const
@ UDS_LOCAL_PATH
A local file path if the KIO worker display files sitting on the local filesystem (but in another hie...
static QString removeAcceleratorMarker(const QString &label)
static bool isKnownProtocol(const QUrl &url)
Returns whether a protocol is installed that is able to handle url.
static bool supportsListing(const QUrl &url)
Returns whether the protocol can list files/objects.
static int maximumItems()
Returns the maximum amount of recent document entries allowed.
static void add(const QUrl &url)
Add a new item to the Recent Document menu.
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static KSharedConfig::Ptr openStateConfig(const QString &fileName=QString())
This combobox shows a number of recent URLs/directories, as well as some default directories.
void setUrls(const QStringList &urls)
Inserts urls into the combobox below the "default urls" (see addDefaultUrl).
void setUrl(const QUrl &url)
Sets the current url.
void setCompletionObject(KCompletion *compObj, bool hsig=true) override
Reimplemented from KComboBox (from KCompletion)
void setMaxItems(int)
Sets how many items should be handled and displayed by the combobox.
This class does completion of URLs including user directories (~user) and environment variables.
QString replacedPath(const QString &text) const
Replaces username and/or environment variables, depending on the current settings and returns the fil...
KUrlComboBox * editor() const
void layoutChanged()
The internal layout and graphical representation of components has changed, either after an url chang...
void returnPressed()
This signal is emitted when the Return or Enter key is pressed.
void urlChanged(const QUrl &url)
Is emitted, if the location URL has been changed e.
Q_SCRIPTABLE QString start(QString train="")
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
KIOCORE_EXPORT QString iconNameForUrl(const QUrl &url)
Return the icon name for a URL.
KIOCORE_EXPORT StatJob * stat(const QUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
KIOCORE_EXPORT QString buildErrorString(int errorCode, const QString &errorText)
Returns a translated error message for errorCode using the additional error information provided by e...
KIOCORE_EXPORT QUrl upUrl(const QUrl &url)
This function is useful to implement the "Up" button in a file manager for example.
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
QString path(const QString &relativePath)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QString dir(const QString &fileClass)
Returns the most recently used directory associated with this file-class.
KIOCORE_EXPORT QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
KIOCORE_EXPORT void add(const QString &fileClass, const QString &directory)
Associates directory with fileClass.
KCOREADDONS_EXPORT QString tildeExpand(const QString &path)
QAction * create(StandardAction id, const Receiver *recvr, Func slot, QObject *parent, std::optional< Qt::ConnectionType > connectionType=std::nullopt)
QString label(StandardShortcut id)
const QList< QKeySequence > & completion()
const QList< QKeySequence > & createFolder()
bool authorizeUrlAction(const QString &action, const QUrl &baseURL, const QUrl &destURL)
Returns whether a certain URL related action is authorized.
void doubleClicked(const QModelIndex &index)
QAbstractItemModel * model() const const
void sliderMoved(int value)
void valueChanged(int value)
bool isChecked() const const
void setShortcut(const QKeySequence &shortcut)
void toggled(bool checked)
void triggered(bool checked)
void setWhatsThis(const QString &what)
char toLatin1() const const
AdjustToContentsOnFirstShow
void editTextChanged(const QString &text)
QLineEdit * lineEdit() const const
bool sendEvent(QObject *receiver, QEvent *event)
QString cleanPath(const QString &path)
QString fromNativeSeparators(const QString &pathName)
QIcon fromTheme(const QString &name)
void setSelection(int start, int length)
void setText(const QString &)
void textChanged(const QString &text)
void textEdited(const QString &text)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
bool isEmpty() const const
qsizetype length() const const
void prepend(parameter_type value)
void reserve(qsizetype size)
QMimeType mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const const
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
QString suffixForFileName(const QString &fileName) const const
bool isValid() const const
bool isValid() const const
bool blockSignals(bool block)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool eventFilter(QObject *watched, QEvent *event)
QObject * parent() const const
bool setProperty(const char *name, QVariant &&value)
bool signalsBlocked() const const
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
void setPattern(const QString &pattern)
QString wildcardToRegularExpression(QStringView pattern, WildcardConversionOptions options)
bool hasMatch() const const
QSize boundedTo(const QSize &otherSize) const const
QSize expandedTo(const QSize &otherSize) const const
void splitterMoved(int pos, int index)
QString writableLocation(StandardLocation type)
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString & prepend(QChar ch)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QString join(QChar separator) const const
void chop(qsizetype length)
bool endsWith(QChar ch) const const
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs) const const
qsizetype length() const const
void truncate(qsizetype length)
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)
QUrl adjusted(FormattingOptions options) const const
QString fileName(ComponentFormattingOptions options) const const
QUrl fromLocalFile(const QString &localFile)
bool isEmpty() const const
bool isLocalFile() const const
bool isParentOf(const QUrl &childUrl) const const
bool isRelative() const const
bool isValid() const const
bool matches(const QUrl &url, FormattingOptions options) const const
QString path(ComponentFormattingOptions options) const const
QUrl resolved(const QUrl &relative) const const
QString scheme() const const
void setPath(const QString &path, ParsingMode mode)
QString toDisplayString(FormattingOptions options) const const
QString toLocalFile() const const
QString url(FormattingOptions options) const const
QVariant fromValue(T &&value)