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 const bool modified = m_locationEdit->lineEdit()->isModified();
905 if (!(m_ops->mode() & KFile::Files)) {
908 setLocationText(QUrl());
915 if (!m_locationEdit->hasFocus()) {
916 setLocationText(m_url);
919 Q_EMIT q->fileHighlighted(m_url);
921 multiSelectionChanged();
922 Q_EMIT q->selectionChanged();
925 m_locationEdit->lineEdit()->setModified(
false);
932 if (!isKeyNavigation && m_operationMode == KFileWidget::Saving) {
933 m_locationEdit->setFocus();
937void KFileWidgetPrivate::fileSelected(
const KFileItem &i)
939 if (!i.
isNull() && i.isDir()) {
943 if (!(m_ops->mode() & KFile::Files)) {
945 setLocationText(QUrl());
948 setLocationText(i.targetUrl());
950 multiSelectionChanged();
951 Q_EMIT q->selectionChanged();
955 if (m_operationMode == KFileWidget::Saving) {
956 m_locationEdit->setFocus();
964void KFileWidgetPrivate::multiSelectionChanged()
966 if (m_locationEdit->hasFocus() && !m_locationEdit->currentText().isEmpty()) {
970 const KFileItemList
list = m_ops->selectedItems();
973 setLocationText(QUrl());
979 setLocationText(
list.
first().targetUrl());
984 for (
const auto &item : list) {
986 urlList.
append(item.targetUrl());
989 setLocationText(urlList);
992void KFileWidgetPrivate::setLocationText(
const QUrl &url)
997 if ((url.
isEmpty() && m_locationEdit->lineEdit()->text().isEmpty()) || m_locationEdit->lineEdit()->text() == escapeDoubleQuotes(url.
fileName())) {
1003 const QSignalBlocker blocker(m_locationEdit);
1009 q->setUrl(directory,
false);
1011 q->setUrl(url,
false);
1014 m_locationEdit->lineEdit()->selectAll();
1015 m_locationEdit->lineEdit()->insert(escapeDoubleQuotes(url.
fileName()));
1016 }
else if (!m_locationEdit->lineEdit()->text().isEmpty()) {
1017 m_locationEdit->clearEditText();
1020 if (m_operationMode == KFileWidget::Saving) {
1021 setNonExtSelection();
1030 relPath.remove(0, basePath.length());
1032 relPath.remove(0, 1);
1043 path.
replace(QStringLiteral(
"\\"), QStringLiteral(
"\\\\"));
1045 path.
replace(QStringLiteral(
"\""), QStringLiteral(
"\\\""));
1049void KFileWidgetPrivate::initDirOpWidgets()
1051 m_opsWidget =
new QWidget(q);
1052 m_opsWidgetLayout =
new QVBoxLayout(m_opsWidget);
1053 m_opsWidgetLayout->setContentsMargins(0, 0, 0, 0);
1054 m_opsWidgetLayout->setSpacing(0);
1056 m_model =
new KFilePlacesModel(q);
1064 m_urlNavigator =
new KUrlNavigator(m_model, QUrl(), m_opsWidget);
1065 m_urlNavigator->setPlacesSelectorVisible(
false);
1068 const auto navWidget =
new QWidget(m_opsWidget);
1069 const auto navLayout =
new QHBoxLayout(navWidget);
1070 navLayout->addWidget(m_urlNavigator);
1076 m_messageWidget =
new KMessageWidget(q);
1078 m_messageWidget->setWordWrap(
true);
1079 m_messageWidget->hide();
1081 auto topSeparator =
new QFrame(q);
1084 m_ops =
new KDirOperator(QUrl(), m_opsWidget);
1085 m_ops->installEventFilter(q);
1086 m_ops->setObjectName(QStringLiteral(
"KFileWidget::ops"));
1087 m_ops->setIsSaving(m_operationMode == KFileWidget::Saving);
1088 m_ops->setNewFileMenuSelectDirWhenAlreadyExist(
true);
1089 m_ops->showOpenWithActions(
true);
1092 auto bottomSparator =
new QFrame(q);
1095 q->connect(m_ops, &KDirOperator::urlEntered, q, [
this](
const QUrl &url) {
1099 fileHighlighted(item, isKeyNavigation);
1101 q->connect(m_ops, &KDirOperator::fileSelected, q, [
this](
const KFileItem &item) {
1104 q->connect(m_ops, &KDirOperator::finishedLoading, q, [
this]() {
1105 slotLoadingFinished();
1108 slotViewKeyEnterReturnPressed();
1112 q->setSelectedUrls(urls);
1119 m_ops->dirLister()->setAutoErrorHandlingEnabled(
false);
1121 m_messageWidget->setText(job->errorString());
1122 m_messageWidget->animatedShow();
1125 m_ops->setupMenu(KDirOperator::SortActions | KDirOperator::FileActions | KDirOperator::ViewActions);
1129 m_opsWidgetLayout->addWidget(m_toolbar);
1130 m_opsWidgetLayout->addWidget(navWidget);
1131 m_opsWidgetLayout->addWidget(m_messageWidget);
1132 m_opsWidgetLayout->addWidget(topSeparator);
1133 m_opsWidgetLayout->addWidget(m_ops);
1134 m_opsWidgetLayout->addWidget(bottomSparator);
1137void KFileWidgetPrivate::initZoomWidget()
1139 m_iconSizeSlider =
new QSlider(q);
1141 m_iconSizeSlider->setMinimumWidth(40);
1143 m_iconSizeSlider->setMinimum(0);
1144 m_iconSizeSlider->setMaximum(m_stdIconSizes.size() - 1);
1145 m_iconSizeSlider->setSingleStep(1);
1146 m_iconSizeSlider->setPageStep(1);
1150 slotIconSizeChanged(m_stdIconSizes[step]);
1154 slotIconSizeSliderMoved(m_stdIconSizes[step]);
1158 slotDirOpIconSizeChanged(iconSize);
1165 changeIconsSize(ZoomOut);
1169 q->addAction(m_zoomOutAction);
1175 changeIconsSize(ZoomIn);
1179 q->addAction(m_zoomInAction);
1182void KFileWidgetPrivate::initToolbar()
1184 m_toolbar =
new QToolBar(m_opsWidget);
1185 m_toolbar->setObjectName(QStringLiteral(
"KFileWidget::toolbar"));
1186 m_toolbar->setMovable(
false);
1197 ->setWhatsThis(
i18n(
"<qt>Click this button to enter the parent folder.<br /><br />"
1198 "For instance, if the current location is file:/home/konqi clicking this "
1199 "button will take you to file:/home.</qt>"));
1201 m_ops->action(
KDirOperator::Back)->setWhatsThis(
i18n(
"Click this button to move backwards one step in the browsing history."));
1202 m_ops->action(
KDirOperator::Forward)->setWhatsThis(
i18n(
"Click this button to move forward one step in the browsing history."));
1204 m_ops->action(
KDirOperator::Reload)->setWhatsThis(
i18n(
"Click this button to reload the contents of the current location."));
1208 m_togglePlacesPanelAction =
new KToggleAction(
i18n(
"Show Places Panel"), q);
1209 q->addAction(m_togglePlacesPanelAction);
1210 m_togglePlacesPanelAction->setShortcut(QKeySequence(
Qt::Key_F9));
1211 q->connect(m_togglePlacesPanelAction, &
QAction::toggled, q, [
this](
bool show) {
1212 togglePlacesPanel(show);
1215 m_toggleBookmarksAction =
new KToggleAction(
i18n(
"Show Bookmarks Button"), q);
1216 q->addAction(m_toggleBookmarksAction);
1217 q->connect(m_toggleBookmarksAction, &
QAction::toggled, q, [
this](
bool show) {
1218 toggleBookmarks(show);
1221 m_toggleQuickFilterAction =
new KToggleAction(
i18n(
"Show Quick Filter"), q);
1222 q->addAction(m_toggleQuickFilterAction);
1224 q->connect(m_toggleQuickFilterAction, &
QAction::toggled, q, [
this](
bool show) {
1225 setQuickFilterVisible(show);
1229 KActionMenu *menu =
new KActionMenu(
QIcon::fromTheme(QStringLiteral(
"configure")),
i18n(
"Options"), q);
1232 i18n(
"<qt>This is the preferences menu for the file dialog. "
1233 "Various options can be accessed from this menu including: <ul>"
1234 "<li>how files are sorted in the list</li>"
1235 "<li>types of view, including icon and list</li>"
1236 "<li>showing of hidden files</li>"
1237 "<li>the Places panel</li>"
1238 "<li>file previews</li>"
1239 "<li>separating folders from files</li></ul></qt>"));
1241 menu->
addAction(m_ops->action(KDirOperator::AllowExpansionInDetailsView));
1242 menu->addSeparator();
1244 menu->
addAction(m_togglePlacesPanelAction);
1245 menu->
addAction(m_toggleQuickFilterAction);
1246 menu->
addAction(m_toggleBookmarksAction);
1252 m_bookmarkButton =
new KActionMenu(
QIcon::fromTheme(QStringLiteral(
"bookmarks")),
i18n(
"Bookmarks"), q);
1254 q->addAction(m_bookmarkButton);
1255 m_bookmarkButton->setWhatsThis(
1256 i18n(
"<qt>This button allows you to bookmark specific locations. "
1257 "Click on this button to open the bookmark menu where you may add, "
1258 "edit or select a bookmark.<br /><br />"
1259 "These bookmarks are specific to the file dialog, but otherwise operate "
1260 "like bookmarks elsewhere in KDE.</qt>"));
1262 QWidget *midSpacer =
new QWidget(q);
1269 m_toolbar->addSeparator();
1270 m_toolbar->addAction(m_ops->action(KDirOperator::ViewIconsView));
1271 m_toolbar->addAction(m_ops->action(KDirOperator::ViewCompactView));
1272 m_toolbar->addAction(m_ops->action(KDirOperator::ViewDetailsView));
1273 m_toolbar->addSeparator();
1274 m_toolbar->addAction(m_ops->action(KDirOperator::ShowPreview));
1276 m_toolbar->addAction(m_bookmarkButton);
1278 m_toolbar->addWidget(midSpacer);
1281 m_toolbar->addAction(m_zoomOutAction);
1282 m_toolbar->addWidget(m_iconSizeSlider);
1283 m_toolbar->addAction(m_zoomInAction);
1284 m_toolbar->addSeparator();
1287 m_toolbar->addAction(menu);
1290 m_toolbar->setMovable(
false);
1293void KFileWidgetPrivate::initLocationWidget()
1295 m_locationLabel =
new QLabel(
i18n(
"&Name:"), q);
1296 m_locationEdit =
new KUrlComboBox(KUrlComboBox::Files,
true, q);
1297 m_locationEdit->installEventFilter(q);
1303 slotLocationChanged(text);
1307 m_locationEdit->lineEdit()->setClearButtonEnabled(
false);
1309 QAction *clearAction =
new QAction(
QIcon::fromTheme(QStringLiteral(
"edit-clear")), {}, m_locationEdit->lineEdit());
1314 clearAction->setVisible(m_locationEdit->lineEdit()->text().length() > 0);
1317 m_okButton->setEnabled(!text.isEmpty());
1320 QAction *undoAction =
new QAction(
QIcon::fromTheme(QStringLiteral(
"edit-undo")),
i18nc(
"@info:tooltip",
"Undo filename change"), m_locationEdit->lineEdit());
1325 undoAction->setVisible(m_locationEdit->lineEdit()->isUndoAvailable());
1328 updateLocationWhatsThis();
1329 m_locationLabel->setBuddy(m_locationEdit);
1331 KUrlCompletion *fileCompletionObj =
new KUrlCompletion(KUrlCompletion::FileCompletion);
1332 m_locationEdit->setCompletionObject(fileCompletionObj);
1333 m_locationEdit->setAutoDeleteCompletionObject(
true);
1336 locationAccepted(text);
1340void KFileWidgetPrivate::initFilterWidget()
1342 m_filterLabel =
new QLabel(q);
1343 m_filterWidget =
new KFileFilterCombo(q);
1350 m_filterLabel->setBuddy(m_filterWidget);
1352 slotMimeFilterChanged();
1355 m_filterDelayTimer.setSingleShot(
true);
1356 m_filterDelayTimer.setInterval(300);
1359 slotMimeFilterChanged();
1363void KFileWidgetPrivate::initQuickFilterWidget()
1365 m_quickFilter =
new QWidget(q);
1367 m_quickFilterLock =
new QToolButton(m_quickFilter);
1368 m_quickFilterLock->setAutoRaise(
true);
1369 m_quickFilterLock->setCheckable(
true);
1370 m_quickFilterLock->setIcon(
QIcon::fromTheme(QStringLiteral(
"object-unlocked")));
1371 m_quickFilterLock->setToolTip(
i18nc(
"@info:tooltip",
"Keep Filter When Changing Folders"));
1373 m_quickFilterEdit =
new QLineEdit(m_quickFilter);
1374 m_quickFilterEdit->setClearButtonEnabled(
true);
1375 m_quickFilterEdit->setPlaceholderText(
i18n(
"Filter by name…"));
1377 slotQuickFilterChanged();
1380 m_quickFilterClose =
new QToolButton(m_quickFilter);
1381 m_quickFilterClose->setAutoRaise(
true);
1382 m_quickFilterClose->setIcon(
QIcon::fromTheme(QStringLiteral(
"dialog-close")));
1383 m_quickFilterClose->setToolTip(
i18nc(
"@info:tooltip",
"Hide Filter Bar"));
1385 setQuickFilterVisible(
false);
1388 QHBoxLayout *hLayout =
new QHBoxLayout(m_quickFilter);
1389 hLayout->setContentsMargins(0, 0, 0, 0);
1390 hLayout->addWidget(m_quickFilterLock);
1391 hLayout->addWidget(m_quickFilterEdit);
1392 hLayout->addWidget(m_quickFilterClose);
1395 m_quickFilter->hide();
1398void KFileWidgetPrivate::setLocationText(
const QList<QUrl> &urlList)
1403 const QSignalBlocker blocker(m_locationEdit);
1405 const QUrl baseUrl = m_ops->
url();
1407 if (urlList.
count() > 1) {
1409 for (
const QUrl &url : urlList) {
1410 urls += QStringLiteral(
"\"%1\" ").
arg(escapeDoubleQuotes(relativePathOrUrl(baseUrl, url)));
1414 m_locationEdit->lineEdit()->selectAll();
1415 m_locationEdit->lineEdit()->insert(urls);
1416 }
else if (urlList.count() == 1) {
1417 const auto url = urlList[0];
1418 m_locationEdit->lineEdit()->selectAll();
1419 m_locationEdit->lineEdit()->insert(escapeDoubleQuotes(relativePathOrUrl(baseUrl, url)));
1420 }
else if (!m_locationEdit->lineEdit()->text().isEmpty()) {
1421 m_locationEdit->clearEditText();
1424 if (m_operationMode == KFileWidget::Saving) {
1425 setNonExtSelection();
1429void KFileWidgetPrivate::updateLocationWhatsThis()
1431 const QString autocompletionWhatsThisText =
i18n(
1432 "<qt>While typing in the text area, you may be presented "
1433 "with possible matches. "
1434 "This feature can be controlled by clicking with the right mouse button "
1435 "and selecting a preferred mode from the <b>Text Completion</b> menu.</qt>");
1437 QString whatsThisText;
1438 if (m_operationMode == KFileWidget::Saving) {
1439 whatsThisText = QLatin1String(
"<qt>") +
i18n(
"This is the name to save the file as.") + autocompletionWhatsThisText;
1440 }
else if (m_ops->mode() & KFile::Files) {
1441 whatsThisText = QLatin1String(
"<qt>")
1442 +
i18n(
"This is the list of files to open. More than "
1443 "one file can be specified by listing several "
1444 "files, separated by spaces.")
1445 + autocompletionWhatsThisText;
1447 whatsThisText = QLatin1String(
"<qt>") +
i18n(
"This is the name of the file to open.") + autocompletionWhatsThisText;
1450 m_locationLabel->setWhatsThis(whatsThisText);
1451 m_locationEdit->setWhatsThis(whatsThisText);
1454void KFileWidgetPrivate::initPlacesPanel()
1460 m_placesDock =
new QDockWidget(
i18nc(
"@title:window",
"Places"), q);
1462 m_placesDock->setTitleBarWidget(
new KDEPrivate::KFileWidgetDockTitleBar(m_placesDock));
1464 m_placesView =
new KFilePlacesView(m_placesDock);
1465 m_placesView->setModel(m_model);
1468 m_placesView->setObjectName(QStringLiteral(
"url bar"));
1469 QObject::connect(m_placesView, &KFilePlacesView::urlChanged, q, [
this](
const QUrl &url) {
1474 m_messageWidget->setText(errorMessage);
1475 m_messageWidget->animatedShow();
1482 m_placesView->setUrl(m_url);
1484 m_placesDock->setWidget(m_placesView);
1485 m_placesViewSplitter->insertWidget(0, m_placesDock);
1488 m_placesViewWidth = m_configGroup.readEntry(SpeedbarWidth, m_placesView->sizeHint().width());
1491 setPlacesViewSplitterSizes();
1494 togglePlacesPanel(visible, m_placesDock);
1498void KFileWidgetPrivate::setPlacesViewSplitterSizes()
1500 if (m_placesViewWidth > 0) {
1501 QList<int> sizes = m_placesViewSplitter->sizes();
1502 sizes[0] = m_placesViewWidth;
1503 sizes[1] = q->width() - m_placesViewWidth - m_placesViewSplitter->handleWidth();
1504 m_placesViewSplitter->setSizes(sizes);
1508void KFileWidgetPrivate::initGUI()
1512 m_boxLayout =
new QVBoxLayout(q);
1513 m_boxLayout->setContentsMargins(0, 0, 0, 0);
1515 m_placesViewSplitter =
new QSplitter(q);
1517 m_placesViewSplitter->setChildrenCollapsible(
false);
1518 m_boxLayout->addWidget(m_placesViewSplitter);
1521 placesViewSplitterMoved(pos, index);
1523 m_placesViewSplitter->insertWidget(0, m_opsWidget);
1525 m_lafBox =
new QFormLayout();
1532 m_lafBox->addRow(m_quickFilter);
1533 m_lafBox->addRow(m_locationLabel, m_locationEdit);
1534 m_lafBox->addRow(m_filterLabel, m_filterWidget);
1536 m_lafBox->addWidget(m_autoSelectExtCheckBox);
1538 m_opsWidgetLayout->addLayout(m_lafBox);
1540 auto hbox =
new QHBoxLayout();
1547 hbox->addStretch(2);
1548 hbox->addWidget(m_okButton);
1549 hbox->addWidget(m_cancelButton);
1551 m_opsWidgetLayout->addLayout(hbox);
1553 auto updateTabOrder = [
this]() {
1555 q->setTabOrder(m_urlNavigator, m_ops);
1557 q->setTabOrder(m_ops, m_autoSelectExtCheckBox);
1558 q->setTabOrder(m_autoSelectExtCheckBox, m_quickFilterLock);
1559 q->setTabOrder(m_quickFilterLock, m_quickFilterEdit);
1560 q->setTabOrder(m_quickFilterEdit, m_quickFilterClose);
1561 q->setTabOrder(m_quickFilterClose, m_locationEdit);
1562 q->setTabOrder(m_locationEdit, m_filterWidget);
1563 q->setTabOrder(m_filterWidget, m_okButton);
1564 q->setTabOrder(m_okButton, m_cancelButton);
1565 q->setTabOrder(m_cancelButton, m_placesView);
1568 const auto toolbarChildren = m_toolbar->children();
1569 QList<QWidget *> toolbarButtons;
1570 for (QObject *obj : std::as_const(toolbarChildren)) {
1571 if (
auto *button = qobject_cast<QToolButton *>(obj)) {
1574 toolbarButtons << button;
1575 }
else if (
auto *slider = qobject_cast<QSlider *>(obj)) {
1576 toolbarButtons << slider;
1580 q->setTabOrder(m_placesView, toolbarButtons.
first());
1584 while (nextIt != toolbarButtons.
constEnd()) {
1585 q->setTabOrder(*it, *nextIt);
1595void KFileWidgetPrivate::slotMimeFilterChanged()
1597 m_filterDelayTimer.stop();
1599 KFileFilter
filter = m_filterWidget->currentFilter();
1601 m_ops->clearFilter();
1603 if (!
filter.mimePatterns().isEmpty()) {
1604 QStringList types =
filter.mimePatterns();
1605 types.
prepend(QStringLiteral(
"inode/directory"));
1606 m_ops->setMimeFilter(types);
1609 updateNameFilter(filter);
1611 updateAutoSelectExtension();
1615 Q_EMIT q->filterChanged(filter);
1618void KFileWidgetPrivate::slotQuickFilterChanged()
1620 m_filterDelayTimer.stop();
1622 KFileFilter
filter(QStringLiteral(
"quickFilter"), QStringList{m_quickFilterEdit->text()}, m_filterWidget->currentFilter().mimePatterns());
1623 m_ops->clearFilter();
1624 m_ops->setMimeFilter(
filter.mimePatterns());
1626 updateNameFilter(filter);
1630 Q_EMIT q->filterChanged(filter);
1633void KFileWidgetPrivate::updateNameFilter(
const KFileFilter &filter)
1635 const auto filePatterns =
filter.filePatterns();
1636 const bool hasRegExSyntax = std::any_of(filePatterns.constBegin(), filePatterns.constEnd(), [](
const QString &filter) {
1638 return filter.contains(QLatin1Char(
'*')) || filter.contains(QLatin1Char(
'?')) || filter.contains(QLatin1Char(
'['));
1641 if (hasRegExSyntax) {
1642 m_ops->setNameFilter(
filter.filePatterns().join(QLatin1Char(
' ')));
1644 m_ops->setNameFilter(QLatin1Char(
'*') + filePatterns.join(QLatin1Char(
'*')) + QLatin1Char(
'*'));
1652 d->m_ops->setUrl(url, clearforward);
1656void KFileWidgetPrivate::urlEntered(
const QUrl &url)
1661 if (pathCombo->
count() != 0) {
1666 if (m_keepLocation) {
1667 const QUrl currentUrl = urlFromString(locationEditCurrentText());
1671 m_locationEdit->lineEdit()->setModified(
true);
1674 m_locationEdit->blockSignals(blocked);
1676 m_urlNavigator->setLocationUrl(url);
1679 KUrlCompletion *
completion =
dynamic_cast<KUrlCompletion *
>(m_locationEdit->completionObject());
1685 m_placesView->setUrl(url);
1688 m_messageWidget->hide();
1691void KFileWidgetPrivate::locationAccepted(
const QString &url)
1698void KFileWidgetPrivate::enterUrl(
const QUrl &url)
1705 Utils::appendSlashToPath(u);
1712 if (q->window()->focusWidget() != m_locationEdit) {
1717 if (!m_quickFilterLock->isChecked()) {
1718 setQuickFilterVisible(
false);
1722void KFileWidgetPrivate::enterUrl(
const QString &url)
1729bool KFileWidgetPrivate::toOverwrite(
const QUrl &url)
1735 bool res = statJob->
exec();
1739 i18n(
"The file \"%1\" already exists. Do you wish to overwrite it?", url.
fileName()),
1740 i18n(
"Overwrite File?"),
1747 m_locationEdit->setFocus();
1748 setNonExtSelection();
1764 d->setLocationText(url);
1777 d->setLocationText(urls);
1780void KFileWidgetPrivate::slotLoadingFinished()
1787 m_ops->blockSignals(
true);
1788 QUrl u(m_ops->url());
1789 if (currentText.
startsWith(QLatin1Char(
'/'))) {
1792 u.
setPath(Utils::concatPaths(m_ops->url().path(), currentText));
1794 m_ops->setCurrentItem(u);
1795 m_ops->blockSignals(
false);
1798void KFileWidgetPrivate::slotLocationChanged(
const QString &text)
1802 m_locationEdit->lineEdit()->setModified(
true);
1804 if (text.
isEmpty() && m_ops->view()) {
1805 m_ops->view()->clearSelection();
1808 if (!m_locationEdit->lineEdit()->text().isEmpty()) {
1809 const QList<QUrl> urlList(tokenize(text));
1810 m_ops->setCurrentItems(urlList);
1820 if (d->m_inAccept) {
1832 if (d->m_inAccept) {
1833 if (d->m_ops->mode() & KFile::Files) {
1834 list = d->m_urlList;
1844 qCDebug(KIO_KFILEWIDGETS_FW) <<
"Tokenizing:" << line;
1848 Utils::appendSlashToPath(baseUrl);
1852 auto addUrl = [baseUrl, &urls](
const QString &partial_name) {
1853 if (partial_name.trimmed().isEmpty()) {
1858 QUrl partial_url(partial_name);
1859 if (!partial_url.isValid()
1860 || partial_url.isRelative()
1862 || (!partial_url.scheme().isEmpty() && (!partial_name.contains(QStringLiteral(
"://")) || !
KProtocolInfo::isKnownProtocol(partial_url.scheme())))) {
1865 partial_url.clear();
1866 partial_url.setPath(partial_name);
1871 if (partial_url.isRelative() || baseUrl.
isParentOf(partial_url)) {
1872 partial_url = baseUrl.
resolved(partial_url);
1875 if (partial_url.isValid()) {
1876 urls.
append(partial_url);
1879 qCDebug(KIO_KFILEWIDGETS_FW) <<
"Discarding Invalid" << partial_url;
1886 QString partial_name;
1887 bool escape =
false;
1888 for (
int i = 0; i < line.
length(); i++) {
1889 const QChar ch = line[i];
1907 if (ch.
toLatin1() ==
'"' && q->mode() != KFile::Mode::File) {
1908 addUrl(partial_name);
1909 partial_name.
clear();
1920 if (!partial_name.
isEmpty()) {
1921 addUrl(partial_name);
1922 partial_name.
clear();
1932 if (d->m_inAccept) {
1933 const QUrl url = d->mostLocalUrl(d->m_url);
1949 if (d->m_inAccept) {
1950 if (d->m_ops->mode() & KFile::Files) {
1952 for (
const auto &u : urls) {
1953 const QUrl url = d->mostLocalUrl(u);
1961 if (d->m_url.isLocalFile()) {
1962 list.
append(d->m_url.toLocalFile());
1972 return d->m_ops->
url();
1979 if (d->m_placesDock) {
1982 d->setPlacesViewSplitterSizes();
1986void KFileWidget::showEvent(
QShowEvent *event)
1988 if (!d->m_hasView) {
1991 d->m_ops->setViewMode(KFile::Default);
1992 d->m_hasView =
true;
1995 d->slotViewDoubleClicked(index);
1998 d->m_ops->clearHistory();
2003bool KFileWidget::eventFilter(
QObject *watched,
QEvent *event)
2012 const auto type =
event->type();
2029 d->m_ops->setMode(m);
2030 if (d->m_ops->dirOnlyMode()) {
2031 d->m_filterWidget->setDefaultFilter(
KFileFilter(
i18n(
"All Folders"), {QStringLiteral(
"*")}, {}));
2033 d->m_filterWidget->setDefaultFilter(
KFileFilter(
i18n(
"All Files"), {QStringLiteral(
"*")}, {}));
2036 d->updateAutoSelectExtension();
2041 return d->m_ops->mode();
2044void KFileWidgetPrivate::readViewConfig()
2058 m_locationEdit->setCompletionMode(cm);
2062 togglePlacesPanel(m_configGroup.readEntry(ShowSpeedbar,
true));
2065 toggleBookmarks(m_configGroup.readEntry(ShowBookmarks,
false));
2068 m_autoSelectExtChecked = m_configGroup.readEntry(AutoSelectExtChecked, DefaultAutoSelectExtChecked);
2069 updateAutoSelectExtension();
2072 m_urlNavigator->setUrlEditable(!m_configGroup.readEntry(BreadcrumbNavigation,
true));
2075 m_urlNavigator->setShowFullPath(m_configGroup.readEntry(ShowFullPath,
false));
2077 int w1 = q->minimumSize().width();
2078 int w2 = m_toolbar->sizeHint().width();
2080 q->setMinimumWidth(w2);
2084void KFileWidgetPrivate::writeViewConfig()
2092 KConfigGroup tmpGroup(&tmp, ConfigGroup);
2094 KUrlComboBox *pathCombo = m_urlNavigator->editor();
2096 tmpGroup.writeEntry(PathComboCompletionMode,
static_cast<int>(pathCombo->
completionMode()));
2097 tmpGroup.writeEntry(LocationComboCompletionMode,
static_cast<int>(m_locationEdit->completionMode()));
2099 const bool showPlacesPanel = m_placesDock && !m_placesDock->
isHidden();
2100 tmpGroup.writeEntry(ShowSpeedbar, showPlacesPanel);
2101 if (m_placesViewWidth > 0) {
2102 tmpGroup.writeEntry(SpeedbarWidth, m_placesViewWidth);
2105 tmpGroup.writeEntry(ShowBookmarks, m_bookmarkHandler !=
nullptr);
2106 tmpGroup.writeEntry(AutoSelectExtChecked, m_autoSelectExtChecked);
2107 tmpGroup.writeEntry(BreadcrumbNavigation, !m_urlNavigator->isUrlEditable());
2108 tmpGroup.writeEntry(ShowFullPath, m_urlNavigator->showFullPath());
2110 m_ops->writeConfig(tmpGroup);
2116void KFileWidgetPrivate::readRecentFiles()
2120 const bool oldState = m_locationEdit->blockSignals(
true);
2121 m_locationEdit->setMaxItems(m_configGroup.readEntry(RecentFilesNumber, DefaultRecentURLsNumber));
2122 m_locationEdit->setUrls(m_stateConfigGroup.readPathEntry(RecentFiles, QStringList()), KUrlComboBox::RemoveBottom);
2123 m_locationEdit->setCurrentIndex(-1);
2124 m_locationEdit->blockSignals(oldState);
2126 KUrlComboBox *combo = m_urlNavigator->editor();
2127 combo->
setUrls(m_stateConfigGroup.readPathEntry(RecentURLs, QStringList()), KUrlComboBox::RemoveTop);
2128 combo->
setMaxItems(m_configGroup.readEntry(RecentURLsNumber, DefaultRecentURLsNumber));
2129 combo->
setUrl(m_ops->url());
2132 KUrlCompletion *
completion =
dynamic_cast<KUrlCompletion *
>(m_locationEdit->completionObject());
2138void KFileWidgetPrivate::saveRecentFiles()
2141 m_stateConfigGroup.writePathEntry(RecentFiles, m_locationEdit->urls());
2143 KUrlComboBox *pathCombo = m_urlNavigator->editor();
2144 m_stateConfigGroup.writePathEntry(RecentURLs, pathCombo->urls());
2149 return d->m_okButton;
2154 return d->m_cancelButton;
2158void KFileWidget::slotCancel()
2160 d->writeViewConfig();
2166 d->m_keepLocation = keep;
2171 return d->m_keepLocation;
2178 d->m_operationMode =
mode;
2179 d->m_keepLocation = (
mode == Saving);
2180 d->m_filterWidget->setEditable(!d->m_hasDefaultFilter ||
mode != Saving);
2181 if (
mode == Opening) {
2183 d->m_okButton->setText(
i18n(
"&Open"));
2188 }
else if (
mode == Saving) {
2190 d->setNonExtSelection();
2194 d->updateLocationWhatsThis();
2195 d->updateAutoSelectExtension();
2198 d->m_ops->setIsSaving(
mode == Saving);
2200 d->updateFilterText();
2205 return d->m_operationMode;
2208void KFileWidgetPrivate::slotAutoSelectExtClicked()
2214 m_autoSelectExtChecked = m_autoSelectExtCheckBox->
isChecked();
2217 updateLocationEditExtension(m_extension );
2220void KFileWidgetPrivate::placesViewSplitterMoved(
int pos,
int index)
2226 if (m_placesDock && index == 1) {
2227 m_placesViewWidth = pos;
2232void KFileWidgetPrivate::activateUrlNavigator()
2236 QLineEdit *lineEdit = m_urlNavigator->editor()->lineEdit();
2241 m_urlNavigator->setUrlEditable(
false);
2243 m_urlNavigator->setUrlEditable(
true);
2244 m_urlNavigator->setFocus();
2249void KFileWidgetPrivate::slotDirOpIconSizeChanged(
int size)
2251 auto beginIt = m_stdIconSizes.cbegin();
2252 auto endIt = m_stdIconSizes.cend();
2253 auto it = std::lower_bound(beginIt, endIt, size);
2254 const int sliderStep = it != endIt ? it - beginIt : 0;
2255 m_iconSizeSlider->setValue(sliderStep);
2256 m_zoomOutAction->setDisabled(it == beginIt);
2257 m_zoomInAction->setDisabled(it == (endIt - 1));
2260void KFileWidgetPrivate::changeIconsSize(ZoomState zoom)
2262 int step = m_iconSizeSlider->value();
2264 if (zoom == ZoomOut) {
2270 if (step ==
static_cast<int>(m_stdIconSizes.size() - 1)) {
2276 m_iconSizeSlider->setValue(step);
2277 slotIconSizeSliderMoved(m_stdIconSizes[step]);
2280void KFileWidgetPrivate::slotIconSizeChanged(
int _value)
2282 m_ops->setIconSize(_value);
2283 m_iconSizeSlider->setToolTip(
i18n(
"Icon size: %1 pixels", _value));
2286void KFileWidgetPrivate::slotIconSizeSliderMoved(
int size)
2290 slotIconSizeChanged(size);
2292 QPoint global(m_iconSizeSlider->rect().topLeft());
2293 global.ry() += m_iconSizeSlider->height() / 2;
2294 QHelpEvent toolTipEvent(
QEvent::ToolTip, QPoint(0, 0), m_iconSizeSlider->mapToGlobal(global));
2298void KFileWidgetPrivate::slotViewDoubleClicked(
const QModelIndex &index)
2301 if (m_operationMode == KFileWidget::Saving && index.
isValid() && m_ops->selectedItems().constFirst().isFile()) {
2306void KFileWidgetPrivate::slotViewKeyEnterReturnPressed()
2310 if (m_operationMode == KFileWidget::Saving && (m_ops->mode() & KFile::File) && m_ops->selectedItems().isEmpty()) {
2359void KFileWidgetPrivate::updateAutoSelectExtension()
2361 if (!m_autoSelectExtCheckBox) {
2374 QString lastExtension = m_extension;
2375 m_extension.
clear();
2378 if ((m_operationMode == KFileWidget::Saving) && (m_ops->mode() & KFile::File)) {
2383 KFileFilter fileFilter = m_filterWidget->currentFilter();
2389 if (currentExtension.
isEmpty()) {
2390 currentExtension = locationEditCurrentText().
section(QLatin1Char(
'.'), -1, -1);
2394 QString defaultExtension;
2395 QStringList extensionList;
2400 defaultExtension = getExtensionFromPatternList(extensionList);
2408 if (!defaultExtension.
isEmpty()) {
2409 defaultExtension.
prepend(QLatin1Char(
'.'));
2414 if ((!currentExtension.
isEmpty() && extensionList.
contains(QLatin1String(
"*.") + currentExtension))) {
2415 m_extension = QLatin1Char(
'.') + currentExtension;
2417 m_extension = defaultExtension;
2427 QString whatsThisExtension;
2428 if (!m_extension.isEmpty()) {
2430 m_autoSelectExtCheckBox->setText(
i18n(
"Automatically select filename e&xtension (%1)", m_extension));
2431 whatsThisExtension =
i18n(
"the extension <b>%1</b>", m_extension);
2433 m_autoSelectExtCheckBox->setEnabled(
true);
2434 m_autoSelectExtCheckBox->setChecked(m_autoSelectExtChecked);
2437 m_autoSelectExtCheckBox->setText(
i18n(
"Automatically select filename e&xtension"));
2438 whatsThisExtension =
i18n(
"a suitable extension");
2440 m_autoSelectExtCheckBox->setChecked(
false);
2441 m_autoSelectExtCheckBox->setEnabled(
false);
2444 const QString locationLabelText = stripUndisplayable(m_locationLabel->text());
2445 m_autoSelectExtCheckBox->setWhatsThis(QLatin1String(
"<qt>")
2446 +
i18n(
"This option enables some convenient features for "
2447 "saving files with extensions:<br />"
2449 "<li>Any extension specified in the <b>%1</b> text "
2450 "area will be updated if you change the file type "
2453 "<li>If no extension is specified in the <b>%2</b> "
2454 "text area when you click "
2455 "<b>Save</b>, %3 will be added to the end of the "
2456 "filename (if the filename does not already exist). "
2457 "This extension is based on the file type that you "
2458 "have chosen to save in.<br />"
2460 "If you do not want KDE to supply an extension for the "
2461 "filename, you can either turn this option off or you "
2462 "can suppress it by adding a period (.) to the end of "
2463 "the filename (the period will be automatically "
2467 "If unsure, keep this option enabled as it makes your "
2468 "files more manageable.",
2472 + QLatin1String(
"</qt>"));
2474 m_autoSelectExtCheckBox->show();
2477 updateLocationEditExtension(lastExtension);
2481 m_autoSelectExtCheckBox->setChecked(
false);
2482 m_autoSelectExtCheckBox->hide();
2489void KFileWidgetPrivate::updateLocationEditExtension(
const QString &lastExtension)
2491 if (!m_autoSelectExtCheckBox->isChecked() || m_extension.isEmpty()) {
2495 const QString urlStr = locationEditCurrentText();
2500 const int fileNameOffset = urlStr.
lastIndexOf(QLatin1Char(
'/')) + 1;
2501 QStringView fileName = QStringView(urlStr).mid(fileNameOffset);
2503 const int dot = fileName.
lastIndexOf(QLatin1Char(
'.'));
2504 const int len = fileName.
length();
2509 const QUrl url = getCompleteUrl(urlStr);
2514 bool result = statJob->
exec();
2533 }
else if (!m_extension.isEmpty() && fileName.
endsWith(m_extension)) {
2534 fileName.
chop(m_extension.length());
2540 const QString newText = QStringView(urlStr).left(fileNameOffset) + fileName + m_extension;
2541 if (newText != locationEditCurrentText()) {
2542 const int idx = m_locationEdit->currentIndex();
2544 m_locationEdit->lineEdit()->selectAll();
2545 m_locationEdit->lineEdit()->insert(newText);
2547 m_locationEdit->setItemText(idx, newText);
2549 m_locationEdit->lineEdit()->setModified(
true);
2559 QRegularExpression rx;
2560 for (
const QString &p : patterns) {
2571void KFileWidgetPrivate::updateFilter()
2573 if ((m_operationMode == KFileWidget::Saving) && (m_ops->mode() & KFile::File)) {
2574 QString urlStr = locationEditCurrentText();
2582 bool matchesCurrentFilter = [
this, urlMimeType, urlStr] {
2583 const KFileFilter
filter = m_filterWidget->currentFilter();
2584 if (
filter.mimePatterns().contains(urlMimeType.
name())) {
2588 QString filename = urlStr.
mid(urlStr.
lastIndexOf(QLatin1Char(
'/')) + 1);
2590 const auto filePatterns =
filter.filePatterns();
2591 const bool hasMatch = std::any_of(filePatterns.cbegin(), filePatterns.cend(), [filename](
const QString &pattern) {
2592 QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(pattern));
2594 return rx.match(filename).hasMatch();
2599 if (matchesCurrentFilter) {
2603 const auto filters = m_filterWidget->filters();
2605 auto filterIt = std::find_if(filters.cbegin(), filters.cend(), [urlStr, urlMimeType](
const KFileFilter &filter) {
2606 if (filter.mimePatterns().contains(urlMimeType.name())) {
2610 QString filename = urlStr.
mid(urlStr.
lastIndexOf(QLatin1Char(
'/')) + 1);
2613 const auto filePatterns =
filter.filePatterns();
2614 const bool hasMatch = std::any_of(filePatterns.cbegin(), filePatterns.cend(), [filename](
const QString &pattern) {
2616 if (pattern == QLatin1String(
"*")) {
2622 return rx.
match(filename).hasMatch();
2628 if (filterIt != filters.cend()) {
2629 m_filterWidget->setCurrentFilter(*filterIt);
2635void KFileWidgetPrivate::appendExtension(
QUrl &url)
2639 if (!m_autoSelectExtCheckBox->isChecked() || m_extension.isEmpty()) {
2650 const int len = fileName.
length();
2651 const int dot = fileName.
lastIndexOf(QLatin1Char(
'.'));
2653 const bool suppressExtension = (dot == len - 1);
2654 const bool unspecifiedExtension = !fileName.
endsWith(m_extension);
2657 if (!(suppressExtension || unspecifiedExtension)) {
2664 bool res = statJob->
exec();
2671 if (suppressExtension) {
2688 else if (unspecifiedExtension) {
2697void KFileWidgetPrivate::addToRecentDocuments()
2699 int m = m_ops->mode();
2703 if (m & KFile::LocalOnly) {
2704 const QStringList files = q->selectedFiles();
2706 for (; it != files.
end() && atmost > 0; ++it) {
2713 const QList<QUrl> urls = q->selectedUrls();
2715 for (; it != urls.
end() && atmost > 0; ++it) {
2716 if ((*it).isValid()) {
2726 return d->m_locationEdit;
2731 return d->m_filterWidget;
2734void KFileWidgetPrivate::togglePlacesPanel(
bool show,
QObject *sender)
2738 m_placesDock->
show();
2744 for (
int rowIndex = 0; rowIndex < model->
rowCount(); rowIndex++) {
2754 if (sender == m_placesDock && m_placesDock && m_placesDock->isVisibleTo(q)) {
2761 m_placesDock->hide();
2766 if (!m_toolbar->actions().contains(homeAction)) {
2767 m_toolbar->insertAction(reloadAction, homeAction);
2771 m_togglePlacesPanelAction->setChecked(show);
2774 m_urlNavigator->setPlacesSelectorVisible(!show);
2777void KFileWidgetPrivate::toggleBookmarks(
bool show)
2780 if (m_bookmarkHandler) {
2783 m_bookmarkHandler =
new KFileBookmarkHandler(q);
2784 q->connect(m_bookmarkHandler, &KFileBookmarkHandler::openUrl, q, [
this](
const QString &path) {
2787 m_bookmarkButton->setMenu(m_bookmarkHandler->menu());
2788 }
else if (m_bookmarkHandler) {
2789 m_bookmarkButton->setMenu(
nullptr);
2790 delete m_bookmarkHandler;
2791 m_bookmarkHandler =
nullptr;
2794 if (m_bookmarkButton) {
2795 m_bookmarkButton->setVisible(show);
2798 m_toggleBookmarksAction->setChecked(show);
2801void KFileWidgetPrivate::setQuickFilterVisible(
bool show)
2803 if (m_quickFilter->isVisible() == show) {
2807 m_filterWidget->setEnabled(!show);
2809 m_quickFilterEdit->setFocus();
2811 m_quickFilterEdit->clear();
2813 m_quickFilterLock->setChecked(
false);
2814 m_ops->dirLister()->setQuickFilterMode(show);
2815 m_toggleQuickFilterAction->setChecked(show);
2822 return getStartUrl(startDir, recentDirClass, fileName);
2828 recentDirClass.
clear();
2832 bool useDefaultStartDir = startDir.
isEmpty();
2833 if (!useDefaultStartDir) {
2851 keyword = urlDir.
mid(1);
2856 recentDirClass = query.arg(keyword);
2872 useDefaultStartDir =
true;
2877 useDefaultStartDir =
true;
2882 if (useDefaultStartDir) {
2883 if (lastDirectory()->isEmpty()) {
2892 || !
QDir(lastDirectory()->toLocalFile()).exists()) {
2896 ret = *lastDirectory();
2906 *lastDirectory() = directory;
2910void KFileWidgetPrivate::setNonExtSelection()
2913 QString filename = locationEditCurrentText();
2920 int lastDot = filename.
lastIndexOf(QLatin1Char(
'.'));
2922 m_locationEdit->lineEdit()->setSelection(0, lastDot);
2924 m_locationEdit->lineEdit()->selectAll();
2931void KFileWidgetPrivate::updateFilterText()
2934 QString whatsThisText;
2936 if (m_operationMode == KFileWidget::Saving && !m_filterWidget->currentFilter().mimePatterns().isEmpty()) {
2937 whatsThisText =
i18n(
"<qt>This is the file type selector. It is used to select the format that the file will be saved as.</qt>");
2939 whatsThisText =
i18n(
"<qt>This is the file type selector. It is used to select the format of the files shown.</qt>");
2942 if (m_filterLabel) {
2943 m_filterLabel->setText(label);
2944 m_filterLabel->setWhatsThis(whatsThisText);
2946 if (m_filterWidget) {
2947 m_filterWidget->setWhatsThis(whatsThisText);
2953 delete d->m_bottomCustomWidget;
2954 d->m_bottomCustomWidget = widget;
2959 d->m_bottomCustomWidget->
setParent(
this);
2961 d->m_opsWidgetLayout->addWidget(d->m_bottomCustomWidget);
2968 setTabOrder(d->m_cancelButton, d->m_bottomCustomWidget);
2969 setTabOrder(d->m_bottomCustomWidget, d->m_urlNavigator);
2974 delete d->m_labeledCustomWidget;
2975 d->m_labeledCustomWidget = widget;
2979 d->m_lafBox->addRow(label, widget);
2987#if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(6, 3)
2990 d->m_configGroup = group;
2991 d->readViewConfig();
2992 d->readRecentFiles();
2996QString KFileWidgetPrivate::locationEditCurrentText()
const
3001QUrl KFileWidgetPrivate::mostLocalUrl(
const QUrl &url)
3009 bool res = statJob->
exec();
3025void KFileWidgetPrivate::setInlinePreviewShown(
bool show)
3027 m_ops->setInlinePreviewShown(show);
3032 d->m_confirmOverwrite = enable;
3037 d->setInlinePreviewShown(
show);
3043 QSize goodSize(48 * fontSize, 30 * fontSize);
3044 const QSize scrnSize = d->screenSize();
3045 QSize minSize(scrnSize / 2);
3046 QSize maxSize(scrnSize * qreal(0.9));
3052 d->m_ops->setViewMode(
mode);
3053 d->m_hasView =
true;
3058 d->m_model->setSupportedSchemes(schemes);
3059 d->m_ops->setSupportedSchemes(schemes);
3060 d->m_urlNavigator->setSupportedSchemes(schemes);
3065 return d->m_model->supportedSchemes();
3068#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 event(QEvent *e)
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)