File indexing completed on 2024-04-28 15:26:39

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1999, 2000 Stephan Kulow <coolo@kde.org>
0004     SPDX-FileCopyrightText: 1999, 2000, 2001, 2002, 2003 Carsten Pfeiffer <pfeiffer@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include <config-kiofilewidgets.h>
0010 #include <defaults-kfile.h> // ConfigGroup, DefaultShowHidden, DefaultDirsFirst, DefaultSortReversed
0011 
0012 #include "../utils_p.h"
0013 
0014 #include "kdirmodel.h"
0015 #include "kdiroperator.h"
0016 #include "kdiroperatordetailview_p.h"
0017 #include "kdiroperatoriconview_p.h"
0018 #include "kdirsortfilterproxymodel.h"
0019 #include "kfileitem.h"
0020 #include "kfilemetapreview_p.h"
0021 #include "knewfilemenu.h"
0022 #include "kpreviewwidgetbase.h"
0023 #include <KActionCollection>
0024 #include <KConfigGroup>
0025 #include <KFileItemActions>
0026 #include <KFileItemListProperties>
0027 #include <KIO/OpenFileManagerWindowJob>
0028 #include <KIO/RenameFileDialog>
0029 #include <KIconLoader>
0030 #include <KJobWidgets>
0031 #include <KLocalizedString>
0032 #include <KMessageBox>
0033 #include <KProtocolManager>
0034 #include <KSharedConfig>
0035 #include <KUrlMimeData>
0036 #include <kfileitemdelegate.h>
0037 #include <kfilepreviewgenerator.h>
0038 #include <kio/copyjob.h>
0039 #include <kio/deletejob.h>
0040 #include <kio/deleteortrashjob.h>
0041 #include <kio/jobuidelegate.h>
0042 #include <kio/previewjob.h>
0043 #include <kpropertiesdialog.h>
0044 
0045 #include <QActionGroup>
0046 #include <QApplication>
0047 #include <QDebug>
0048 #include <QHeaderView>
0049 #include <QListView>
0050 #include <QMenu>
0051 #include <QMimeDatabase>
0052 #include <QProgressBar>
0053 #include <QRegularExpression>
0054 #include <QScrollBar>
0055 #include <QSplitter>
0056 #include <QTimer>
0057 #include <QWheelEvent>
0058 
0059 #include <memory>
0060 
0061 template class QHash<QString, KFileItem>;
0062 
0063 // QDir::SortByMask is not only undocumented, it also omits QDir::Type which  is another
0064 // sorting mode.
0065 static const int QDirSortMask = QDir::SortByMask | QDir::Type;
0066 
0067 class KDirOperatorPrivate
0068 {
0069 public:
0070     explicit KDirOperatorPrivate(KDirOperator *qq)
0071         : q(qq)
0072     {
0073         KConfigGroup cg(KSharedConfig::openConfig(), "SmallIcons");
0074         m_iconSize = cg.readEntry("Size", static_cast<int>(KIconLoader::SizeSmall));
0075     }
0076 
0077     ~KDirOperatorPrivate();
0078 
0079     enum InlinePreviewState {
0080         ForcedToFalse = 0,
0081         ForcedToTrue,
0082         NotForced,
0083     };
0084 
0085     // private methods
0086     bool checkPreviewInternal() const;
0087     bool openUrl(const QUrl &url, KDirLister::OpenUrlFlags flags = KDirLister::NoFlags);
0088     int sortColumn() const;
0089     Qt::SortOrder sortOrder() const;
0090     void updateSorting(QDir::SortFlags sort);
0091 
0092     bool isReadable(const QUrl &url);
0093     bool isSchemeSupported(const QString &scheme) const;
0094 
0095     QPoint progressBarPos() const;
0096 
0097     KFile::FileView allViews();
0098 
0099     QMetaObject::Connection m_connection;
0100 
0101     // A pair to store zoom settings for view kinds
0102     struct ZoomSettingsForView {
0103         QString name;
0104         int defaultValue;
0105     };
0106 
0107     // private slots
0108     void slotDetailedView();
0109     void slotSimpleView();
0110     void slotTreeView();
0111     void slotDetailedTreeView();
0112     void slotIconsView();
0113     void slotCompactView();
0114     void slotDetailsView();
0115     void slotToggleHidden(bool);
0116     void slotToggleAllowExpansion(bool);
0117     void togglePreview(bool);
0118     void toggleInlinePreviews(bool);
0119     void slotOpenFileManager();
0120     void slotSortByName();
0121     void slotSortBySize();
0122     void slotSortByDate();
0123     void slotSortByType();
0124     void slotSortReversed(bool doReverse);
0125     void slotToggleDirsFirst();
0126     void slotToggleIconsView();
0127     void slotToggleCompactView();
0128     void slotToggleDetailsView();
0129     void slotToggleIgnoreCase();
0130     void slotStarted();
0131     void slotProgress(int);
0132     void slotShowProgress();
0133     void slotIOFinished();
0134     void slotCanceled();
0135     void slotRedirected(const QUrl &);
0136     void slotProperties();
0137     void slotActivated(const QModelIndex &);
0138     void slotSelectionChanged();
0139     void openContextMenu(const QPoint &);
0140     void triggerPreview(const QModelIndex &);
0141     void showPreview();
0142     void slotSplitterMoved(int, int);
0143     void assureVisibleSelection();
0144     void synchronizeSortingState(int, Qt::SortOrder);
0145     void slotChangeDecorationPosition();
0146     void slotExpandToUrl(const QModelIndex &);
0147     void slotItemsChanged();
0148     void slotDirectoryCreated(const QUrl &);
0149     void slotAskUserDeleteResult(bool allowDelete, const QList<QUrl> &urls, KIO::AskUserActionInterface::DeletionType deletionType, QWidget *parent);
0150 
0151     int iconSizeForViewType(QAbstractItemView *itemView) const;
0152     void writeIconZoomSettingsIfNeeded();
0153     ZoomSettingsForView zoomSettingsForView() const;
0154 
0155     QList<QAction *> insertOpenWithActions();
0156 
0157     // private members
0158     KDirOperator *const q;
0159     QStack<QUrl *> m_backStack; ///< Contains all URLs you can reach with the back button.
0160     QStack<QUrl *> m_forwardStack; ///< Contains all URLs you can reach with the forward button.
0161 
0162     QModelIndex m_lastHoveredIndex;
0163 
0164     KDirLister *m_dirLister = nullptr;
0165     QUrl m_currUrl;
0166 
0167     KCompletion m_completion;
0168     KCompletion m_dirCompletion;
0169     QDir::SortFlags m_sorting;
0170     QStyleOptionViewItem::Position m_decorationPosition = QStyleOptionViewItem::Left;
0171 
0172     QSplitter *m_splitter = nullptr;
0173 
0174     QAbstractItemView *m_itemView = nullptr;
0175     KDirModel *m_dirModel = nullptr;
0176     KDirSortFilterProxyModel *m_proxyModel = nullptr;
0177 
0178     KFileItemList m_pendingMimeTypes;
0179 
0180     // the enum KFile::FileView as an int
0181     int m_viewKind;
0182     int m_defaultView;
0183 
0184     KFile::Modes m_mode;
0185     QProgressBar *m_progressBar = nullptr;
0186 
0187     KPreviewWidgetBase *m_preview = nullptr;
0188     QUrl m_previewUrl;
0189     int m_previewWidth = 0;
0190 
0191     bool m_completeListDirty = false;
0192     bool m_followNewDirectories = true;
0193     bool m_followSelectedDirectories = true;
0194     bool m_onlyDoubleClickSelectsFiles = !qApp->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick);
0195 
0196     QUrl m_lastUrl; // used for highlighting a directory on back/cdUp
0197 
0198     QTimer *m_progressDelayTimer = nullptr;
0199     KActionMenu *m_actionMenu = nullptr;
0200     KActionCollection *m_actionCollection = nullptr;
0201     KNewFileMenu *m_newFileMenu = nullptr;
0202     KConfigGroup *m_configGroup = nullptr;
0203     KFilePreviewGenerator *m_previewGenerator = nullptr;
0204     KActionMenu *m_decorationMenu = nullptr;
0205     KToggleAction *m_leftAction = nullptr;
0206     KFileItemActions *m_itemActions = nullptr;
0207 
0208     int m_dropOptions = 0;
0209     int m_iconSize = 0;
0210     InlinePreviewState m_inlinePreviewState = NotForced;
0211     bool m_dirHighlighting = true;
0212     bool m_showPreviews = false;
0213     bool m_shouldFetchForItems = false;
0214     bool m_isSaving = false;
0215     bool m_showOpenWithActions = false;
0216 
0217     QList<QUrl> m_itemsToBeSetAsCurrent;
0218     QStringList m_supportedSchemes;
0219 
0220     QHash<KDirOperator::Action, QAction *> m_actions;
0221 };
0222 
0223 KDirOperatorPrivate::~KDirOperatorPrivate()
0224 {
0225     if (m_itemView) {
0226         // fix libc++ crash: its unique_ptr implementation has already set 'd' to null
0227         // and the event filter will get a QEvent::Leave event if we don't remove it.
0228         m_itemView->removeEventFilter(q);
0229         m_itemView->viewport()->removeEventFilter(q);
0230     }
0231 
0232     delete m_itemView;
0233     m_itemView = nullptr;
0234 
0235     // TODO:
0236     // if (configGroup) {
0237     //     itemView->writeConfig(configGroup);
0238     // }
0239 
0240     qDeleteAll(m_backStack);
0241     qDeleteAll(m_forwardStack);
0242 
0243     // The parent KDirOperator will delete these
0244     m_preview = nullptr;
0245     m_proxyModel = nullptr;
0246     m_dirModel = nullptr;
0247     m_progressDelayTimer = nullptr;
0248 
0249     m_dirLister = nullptr; // deleted by KDirModel
0250 
0251     delete m_configGroup;
0252     m_configGroup = nullptr;
0253 }
0254 
0255 QPoint KDirOperatorPrivate::progressBarPos() const
0256 {
0257     const int frameWidth = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0258     return QPoint(frameWidth, q->height() - m_progressBar->height() - frameWidth);
0259 }
0260 
0261 KDirOperator::KDirOperator(const QUrl &_url, QWidget *parent)
0262     : QWidget(parent)
0263     , d(new KDirOperatorPrivate(this))
0264 {
0265     d->m_splitter = new QSplitter(this);
0266     d->m_splitter->setChildrenCollapsible(false);
0267     connect(d->m_splitter, &QSplitter::splitterMoved, this, [this](int pos, int index) {
0268         d->slotSplitterMoved(pos, index);
0269     });
0270 
0271     d->m_preview = nullptr;
0272 
0273     d->m_mode = KFile::File;
0274     d->m_viewKind = KFile::Simple;
0275 
0276     if (_url.isEmpty()) { // no dir specified -> current dir
0277         QString strPath = QDir::currentPath();
0278         strPath.append(QLatin1Char('/'));
0279         d->m_currUrl = QUrl::fromLocalFile(strPath);
0280     } else {
0281         d->m_currUrl = _url;
0282         if (d->m_currUrl.scheme().isEmpty()) {
0283             d->m_currUrl.setScheme(QStringLiteral("file"));
0284         }
0285 
0286         // make sure we have a trailing slash!
0287         Utils::appendSlashToPath(d->m_currUrl);
0288     }
0289 
0290     // We set the direction of this widget to LTR, since even on RTL desktops
0291     // viewing directory listings in RTL mode makes people's head explode.
0292     // Is this the correct place? Maybe it should be in some lower level widgets...?
0293     setLayoutDirection(Qt::LeftToRight);
0294     setDirLister(new KDirLister());
0295 
0296     connect(&d->m_completion, &KCompletion::match, this, &KDirOperator::slotCompletionMatch);
0297 
0298     d->m_progressBar = new QProgressBar(this);
0299     d->m_progressBar->setObjectName(QStringLiteral("d->m_progressBar"));
0300     d->m_progressBar->adjustSize();
0301     const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0302     d->m_progressBar->move(frameWidth, height() - d->m_progressBar->height() - frameWidth);
0303 
0304     d->m_progressDelayTimer = new QTimer(this);
0305     d->m_progressDelayTimer->setObjectName(QStringLiteral("d->m_progressBar delay timer"));
0306     connect(d->m_progressDelayTimer, &QTimer::timeout, this, [this]() {
0307         d->slotShowProgress();
0308     });
0309 
0310     d->m_completeListDirty = false;
0311 
0312     // action stuff
0313     setupActions();
0314     setupMenu();
0315 
0316     d->m_sorting = QDir::NoSort; // so updateSorting() doesn't think nothing has changed
0317     d->updateSorting(QDir::Name | QDir::DirsFirst);
0318 
0319     setFocusPolicy(Qt::WheelFocus);
0320     setAcceptDrops(true);
0321 }
0322 
0323 KDirOperator::~KDirOperator()
0324 {
0325     resetCursor();
0326     disconnect(d->m_dirLister, nullptr, this, nullptr);
0327 }
0328 
0329 void KDirOperator::setSorting(QDir::SortFlags spec)
0330 {
0331     d->updateSorting(spec);
0332 }
0333 
0334 QDir::SortFlags KDirOperator::sorting() const
0335 {
0336     return d->m_sorting;
0337 }
0338 
0339 bool KDirOperator::isRoot() const
0340 {
0341 #ifdef Q_OS_WIN
0342     if (url().isLocalFile()) {
0343         const QString path = url().toLocalFile();
0344         if (path.length() == 3) {
0345             return (path[0].isLetter() && path[1] == QLatin1Char(':') && path[2] == QLatin1Char('/'));
0346         }
0347         return false;
0348     } else
0349 #endif
0350         return url().path() == QLatin1String("/");
0351 }
0352 
0353 KDirLister *KDirOperator::dirLister() const
0354 {
0355     return d->m_dirLister;
0356 }
0357 
0358 void KDirOperator::resetCursor()
0359 {
0360     if (qApp) {
0361         QApplication::restoreOverrideCursor();
0362     }
0363     d->m_progressBar->hide();
0364 }
0365 
0366 void KDirOperator::sortByName()
0367 {
0368     d->updateSorting((d->m_sorting & ~QDirSortMask) | QDir::Name);
0369 }
0370 
0371 void KDirOperator::sortBySize()
0372 {
0373     d->updateSorting((d->m_sorting & ~QDirSortMask) | QDir::Size);
0374 }
0375 
0376 void KDirOperator::sortByDate()
0377 {
0378     d->updateSorting((d->m_sorting & ~QDirSortMask) | QDir::Time);
0379 }
0380 
0381 void KDirOperator::sortByType()
0382 {
0383     d->updateSorting((d->m_sorting & ~QDirSortMask) | QDir::Type);
0384 }
0385 
0386 void KDirOperator::sortReversed()
0387 {
0388     // toggle it, hence the inversion of current state
0389     d->slotSortReversed(!(d->m_sorting & QDir::Reversed));
0390 }
0391 
0392 void KDirOperator::toggleDirsFirst()
0393 {
0394     d->slotToggleDirsFirst();
0395 }
0396 
0397 void KDirOperator::toggleIgnoreCase()
0398 {
0399     if (d->m_proxyModel != nullptr) {
0400         Qt::CaseSensitivity cs = d->m_proxyModel->sortCaseSensitivity();
0401         cs = (cs == Qt::CaseSensitive) ? Qt::CaseInsensitive : Qt::CaseSensitive;
0402         d->m_proxyModel->setSortCaseSensitivity(cs);
0403     }
0404 }
0405 
0406 void KDirOperator::updateSelectionDependentActions()
0407 {
0408     const bool hasSelection = (d->m_itemView != nullptr) && d->m_itemView->selectionModel()->hasSelection();
0409     action(KDirOperator::Rename)->setEnabled(hasSelection);
0410     action(KDirOperator::Trash)->setEnabled(hasSelection);
0411     action(KDirOperator::Delete)->setEnabled(hasSelection);
0412     action(KDirOperator::Properties)->setEnabled(hasSelection);
0413 }
0414 
0415 void KDirOperator::setPreviewWidget(KPreviewWidgetBase *w)
0416 {
0417     const bool showPreview = (w != nullptr);
0418     if (showPreview) {
0419         d->m_viewKind = (d->m_viewKind | KFile::PreviewContents);
0420     } else {
0421         d->m_viewKind = (d->m_viewKind & ~KFile::PreviewContents);
0422     }
0423 
0424     delete d->m_preview;
0425     d->m_preview = w;
0426 
0427     if (w) {
0428         d->m_splitter->addWidget(w);
0429     }
0430 
0431     KToggleAction *previewAction = static_cast<KToggleAction *>(action(ShowPreviewPanel));
0432     previewAction->setEnabled(showPreview);
0433     previewAction->setChecked(showPreview);
0434     setViewMode(static_cast<KFile::FileView>(d->m_viewKind));
0435 }
0436 
0437 KFileItemList KDirOperator::selectedItems() const
0438 {
0439     KFileItemList itemList;
0440     if (d->m_itemView == nullptr) {
0441         return itemList;
0442     }
0443 
0444     const QItemSelection selection = d->m_proxyModel->mapSelectionToSource(d->m_itemView->selectionModel()->selection());
0445 
0446     const QModelIndexList indexList = selection.indexes();
0447     for (const QModelIndex &index : indexList) {
0448         KFileItem item = d->m_dirModel->itemForIndex(index);
0449         if (!item.isNull()) {
0450             itemList.append(item);
0451         }
0452     }
0453 
0454     return itemList;
0455 }
0456 
0457 bool KDirOperator::isSelected(const KFileItem &item) const
0458 {
0459     if ((item.isNull()) || (d->m_itemView == nullptr)) {
0460         return false;
0461     }
0462 
0463     const QModelIndex dirIndex = d->m_dirModel->indexForItem(item);
0464     const QModelIndex proxyIndex = d->m_proxyModel->mapFromSource(dirIndex);
0465     return d->m_itemView->selectionModel()->isSelected(proxyIndex);
0466 }
0467 
0468 int KDirOperator::numDirs() const
0469 {
0470     return (d->m_dirLister == nullptr) ? 0 : d->m_dirLister->directories().count();
0471 }
0472 
0473 int KDirOperator::numFiles() const
0474 {
0475     return (d->m_dirLister == nullptr) ? 0 : d->m_dirLister->items().count() - numDirs();
0476 }
0477 
0478 KCompletion *KDirOperator::completionObject() const
0479 {
0480     return const_cast<KCompletion *>(&d->m_completion);
0481 }
0482 
0483 KCompletion *KDirOperator::dirCompletionObject() const
0484 {
0485     return const_cast<KCompletion *>(&d->m_dirCompletion);
0486 }
0487 
0488 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
0489 KActionCollection *KDirOperator::actionCollection() const
0490 {
0491     return d->m_actionCollection;
0492 }
0493 #endif
0494 
0495 QAction *KDirOperator::action(KDirOperator::Action action) const
0496 {
0497     return d->m_actions[action];
0498 }
0499 
0500 QList<QAction *> KDirOperator::allActions() const
0501 {
0502     return d->m_actions.values();
0503 }
0504 
0505 KFile::FileView KDirOperatorPrivate::allViews()
0506 {
0507     return static_cast<KFile::FileView>(KFile::Simple | KFile::Detail | KFile::Tree | KFile::DetailTree);
0508 }
0509 
0510 void KDirOperatorPrivate::slotDetailedView()
0511 {
0512     // save old zoom settings
0513     writeIconZoomSettingsIfNeeded();
0514 
0515     KFile::FileView view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Detail);
0516     q->setViewMode(view);
0517 }
0518 
0519 void KDirOperatorPrivate::slotSimpleView()
0520 {
0521     // save old zoom settings
0522     writeIconZoomSettingsIfNeeded();
0523 
0524     KFile::FileView view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Simple);
0525     q->setViewMode(view);
0526 }
0527 
0528 void KDirOperatorPrivate::slotTreeView()
0529 {
0530     // save old zoom settings
0531     writeIconZoomSettingsIfNeeded();
0532 
0533     KFile::FileView view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Tree);
0534     q->setViewMode(view);
0535 }
0536 
0537 void KDirOperatorPrivate::slotDetailedTreeView()
0538 {
0539     // save old zoom settings
0540     writeIconZoomSettingsIfNeeded();
0541 
0542     KFile::FileView view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::DetailTree);
0543     q->setViewMode(view);
0544 }
0545 
0546 void KDirOperatorPrivate::slotToggleAllowExpansion(bool allow)
0547 {
0548     KFile::FileView view = KFile::Detail;
0549     if (allow) {
0550         view = KFile::DetailTree;
0551     }
0552     q->setViewMode(view);
0553 }
0554 
0555 void KDirOperatorPrivate::slotToggleHidden(bool show)
0556 {
0557     m_dirLister->setShowHiddenFiles(show);
0558     q->updateDir();
0559     assureVisibleSelection();
0560 }
0561 
0562 void KDirOperatorPrivate::togglePreview(bool on)
0563 {
0564     if (on) {
0565         m_viewKind |= KFile::PreviewContents;
0566         if (m_preview == nullptr) {
0567             m_preview = new KFileMetaPreview(q);
0568             q->action(KDirOperator::ShowPreviewPanel)->setChecked(true);
0569             m_splitter->addWidget(m_preview);
0570         }
0571 
0572         m_preview->show();
0573 
0574         auto assureVisFunc = [this]() {
0575             assureVisibleSelection();
0576         };
0577         QMetaObject::invokeMethod(q, assureVisFunc, Qt::QueuedConnection);
0578         if (m_itemView != nullptr) {
0579             const QModelIndex index = m_itemView->selectionModel()->currentIndex();
0580             if (index.isValid()) {
0581                 triggerPreview(index);
0582             }
0583         }
0584     } else if (m_preview != nullptr) {
0585         m_viewKind = m_viewKind & ~KFile::PreviewContents;
0586         m_preview->hide();
0587     }
0588 }
0589 
0590 void KDirOperatorPrivate::toggleInlinePreviews(bool show)
0591 {
0592     if (m_showPreviews == show) {
0593         return;
0594     }
0595 
0596     m_showPreviews = show;
0597 
0598     if (!m_previewGenerator) {
0599         return;
0600     }
0601 
0602     m_previewGenerator->setPreviewShown(show);
0603 }
0604 
0605 void KDirOperatorPrivate::slotOpenFileManager()
0606 {
0607     const KFileItemList list = q->selectedItems();
0608     if (list.isEmpty()) {
0609         KIO::highlightInFileManager({m_currUrl.adjusted(QUrl::StripTrailingSlash)});
0610     } else {
0611         KIO::highlightInFileManager(list.urlList());
0612     }
0613 }
0614 
0615 void KDirOperatorPrivate::slotSortByName()
0616 {
0617     q->sortByName();
0618 }
0619 
0620 void KDirOperatorPrivate::slotSortBySize()
0621 {
0622     q->sortBySize();
0623 }
0624 
0625 void KDirOperatorPrivate::slotSortByDate()
0626 {
0627     q->sortByDate();
0628 }
0629 
0630 void KDirOperatorPrivate::slotSortByType()
0631 {
0632     q->sortByType();
0633 }
0634 
0635 void KDirOperatorPrivate::slotSortReversed(bool doReverse)
0636 {
0637     QDir::SortFlags s = m_sorting & ~QDir::Reversed;
0638     if (doReverse) {
0639         s |= QDir::Reversed;
0640     }
0641     updateSorting(s);
0642 }
0643 
0644 void KDirOperatorPrivate::slotToggleDirsFirst()
0645 {
0646     QDir::SortFlags s = (m_sorting ^ QDir::DirsFirst);
0647     updateSorting(s);
0648 }
0649 
0650 void KDirOperatorPrivate::slotIconsView()
0651 {
0652     // save old zoom settings
0653     writeIconZoomSettingsIfNeeded();
0654 
0655     // Put the icons on top
0656     q->action(KDirOperator::DecorationAtTop)->setChecked(true);
0657     m_decorationPosition = QStyleOptionViewItem::Top;
0658 
0659     // Switch to simple view
0660     KFile::FileView fileView = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Simple);
0661     q->setViewMode(fileView);
0662 }
0663 
0664 void KDirOperatorPrivate::slotCompactView()
0665 {
0666     // save old zoom settings
0667     writeIconZoomSettingsIfNeeded();
0668 
0669     // Put the icons on the side
0670     q->action(KDirOperator::DecorationAtTop)->setChecked(true);
0671     m_decorationPosition = QStyleOptionViewItem::Left;
0672 
0673     // Switch to simple view
0674     KFile::FileView fileView = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Simple);
0675     q->setViewMode(fileView);
0676 }
0677 
0678 void KDirOperatorPrivate::slotDetailsView()
0679 {
0680     // save old zoom settings
0681     writeIconZoomSettingsIfNeeded();
0682 
0683     KFile::FileView view;
0684     if (q->action(KDirOperator::AllowExpansionInDetailsView)->isChecked()) {
0685         view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::DetailTree);
0686     } else {
0687         view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Detail);
0688     }
0689     q->setViewMode(view);
0690 }
0691 
0692 void KDirOperatorPrivate::slotToggleIgnoreCase()
0693 {
0694     // TODO: port to Qt4's QAbstractItemView
0695     /*if ( !d->fileView )
0696       return;
0697 
0698     QDir::SortFlags sorting = d->fileView->sorting();
0699     if ( !KFile::isSortCaseInsensitive( sorting ) )
0700         d->fileView->setSorting( sorting | QDir::IgnoreCase );
0701     else
0702         d->fileView->setSorting( sorting & ~QDir::IgnoreCase );
0703     d->sorting = d->fileView->sorting();*/
0704 }
0705 
0706 void KDirOperator::mkdir()
0707 {
0708     d->m_newFileMenu->setWorkingDirectory(url());
0709     d->m_newFileMenu->createDirectory();
0710 }
0711 
0712 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 78)
0713 bool KDirOperator::mkdir(const QString &directory, bool enterDirectory)
0714 {
0715     // Creates "directory", relative to the current directory (d->currUrl).
0716     // The given path may contain any number directories, existent or not.
0717     // They will all be created, if possible.
0718 
0719     // TODO: very similar to KDirSelectDialog::Private::slotMkdir
0720 
0721     bool writeOk = false;
0722     bool exists = false;
0723     QUrl folderurl(d->m_currUrl);
0724 
0725     const QStringList dirs = directory.split(QLatin1Char('/'), Qt::SkipEmptyParts);
0726     QStringList::ConstIterator it = dirs.begin();
0727 
0728     for (; it != dirs.end(); ++it) {
0729         folderurl.setPath(Utils::concatPaths(folderurl.path(), *it));
0730         if (folderurl.isLocalFile()) {
0731             exists = QFile::exists(folderurl.toLocalFile());
0732         } else {
0733             KIO::StatJob *job = KIO::stat(folderurl);
0734             KJobWidgets::setWindow(job, this);
0735             job->setDetails(KIO::StatNoDetails); // We only want to know if it exists
0736             job->setSide(KIO::StatJob::DestinationSide);
0737             exists = job->exec();
0738         }
0739 
0740         if (!exists) {
0741             KIO::Job *job = KIO::mkdir(folderurl);
0742             KJobWidgets::setWindow(job, this);
0743             writeOk = job->exec();
0744         }
0745     }
0746 
0747     if (exists) { // url was already existent
0748         KMessageBox::error(d->m_itemView, i18n("A file or folder named %1 already exists.", folderurl.toDisplayString(QUrl::PreferLocalFile)));
0749     } else if (!writeOk) {
0750         KMessageBox::error(d->m_itemView,
0751                            i18n("You do not have permission to "
0752                                 "create that folder."));
0753     } else if (enterDirectory) {
0754         setUrl(folderurl, true);
0755     }
0756 
0757     return writeOk;
0758 }
0759 #endif
0760 
0761 KIO::DeleteJob *KDirOperator::del(const KFileItemList &items, QWidget *parent, bool ask, bool showProgress)
0762 {
0763     if (items.isEmpty()) {
0764         KMessageBox::information(parent, i18n("You did not select a file to delete."), i18n("Nothing to Delete"));
0765         return nullptr;
0766     }
0767 
0768     if (parent == nullptr) {
0769         parent = this;
0770     }
0771 
0772     const QList<QUrl> urls = items.urlList();
0773 
0774     bool doIt = !ask;
0775     if (ask) {
0776         KIO::JobUiDelegate uiDelegate(KIO::JobUiDelegate::Version::V2);
0777         uiDelegate.setWindow(parent);
0778         doIt = uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::DefaultConfirmation);
0779     }
0780 
0781     if (doIt) {
0782         KIO::JobFlags flags = showProgress ? KIO::DefaultFlags : KIO::HideProgressInfo;
0783         KIO::DeleteJob *job = KIO::del(urls, flags);
0784         KJobWidgets::setWindow(job, this);
0785         job->uiDelegate()->setAutoErrorHandlingEnabled(true);
0786         return job;
0787     }
0788 
0789     return nullptr;
0790 }
0791 
0792 void KDirOperator::deleteSelected()
0793 {
0794     const QList<QUrl> urls = selectedItems().urlList();
0795     if (urls.isEmpty()) {
0796         KMessageBox::information(this, i18n("You did not select a file to delete."), i18n("Nothing to Delete"));
0797         return;
0798     }
0799 
0800     using Iface = KIO::AskUserActionInterface;
0801     auto *deleteJob = new KIO::DeleteOrTrashJob(urls, Iface::Delete, Iface::DefaultConfirmation, this);
0802     deleteJob->start();
0803 }
0804 
0805 KIO::CopyJob *KDirOperator::trash(const KFileItemList &items, QWidget *parent, bool ask, bool showProgress)
0806 {
0807     if (items.isEmpty()) {
0808         KMessageBox::information(parent, i18n("You did not select a file to trash."), i18n("Nothing to Trash"));
0809         return nullptr;
0810     }
0811 
0812     const QList<QUrl> urls = items.urlList();
0813 
0814     bool doIt = !ask;
0815     if (ask) {
0816         KIO::JobUiDelegate uiDelegate(KIO::JobUiDelegate::Version::V2);
0817         uiDelegate.setWindow(parent);
0818         doIt = uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Trash, KIO::JobUiDelegate::DefaultConfirmation);
0819     }
0820 
0821     if (doIt) {
0822         KIO::JobFlags flags = showProgress ? KIO::DefaultFlags : KIO::HideProgressInfo;
0823         KIO::CopyJob *job = KIO::trash(urls, flags);
0824         KJobWidgets::setWindow(job, this);
0825         job->uiDelegate()->setAutoErrorHandlingEnabled(true);
0826         return job;
0827     }
0828 
0829     return nullptr;
0830 }
0831 
0832 KFilePreviewGenerator *KDirOperator::previewGenerator() const
0833 {
0834     return d->m_previewGenerator;
0835 }
0836 
0837 void KDirOperator::setInlinePreviewShown(bool show)
0838 {
0839     d->m_inlinePreviewState = show ? KDirOperatorPrivate::ForcedToTrue : KDirOperatorPrivate::ForcedToFalse;
0840 }
0841 
0842 bool KDirOperator::isInlinePreviewShown() const
0843 {
0844     return d->m_showPreviews;
0845 }
0846 
0847 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 76)
0848 int KDirOperator::iconsZoom() const
0849 {
0850     const int stepSize = (KIconLoader::SizeEnormous - KIconLoader::SizeSmall) / 100;
0851     const int zoom = (d->m_iconSize / stepSize) - KIconLoader::SizeSmall;
0852     return zoom;
0853 }
0854 #endif
0855 
0856 int KDirOperator::iconSize() const
0857 {
0858     return d->m_iconSize;
0859 }
0860 
0861 void KDirOperator::setIsSaving(bool isSaving)
0862 {
0863     d->m_isSaving = isSaving;
0864 }
0865 
0866 bool KDirOperator::isSaving() const
0867 {
0868     return d->m_isSaving;
0869 }
0870 
0871 void KDirOperator::renameSelected()
0872 {
0873     if (d->m_itemView == nullptr) {
0874         return;
0875     }
0876 
0877     const KFileItemList items = selectedItems();
0878     if (items.isEmpty()) {
0879         return;
0880     }
0881 
0882     KIO::RenameFileDialog *dialog = new KIO::RenameFileDialog(items, this);
0883     connect(dialog, &KIO::RenameFileDialog::renamingFinished, this, [this](const QList<QUrl> &urls) {
0884         d->assureVisibleSelection();
0885         Q_EMIT renamingFinished(urls);
0886     });
0887 
0888     dialog->open();
0889 }
0890 
0891 void KDirOperator::trashSelected()
0892 {
0893     if (d->m_itemView == nullptr) {
0894         return;
0895     }
0896 
0897     if (QApplication::keyboardModifiers() & Qt::ShiftModifier) {
0898         deleteSelected();
0899         return;
0900     }
0901 
0902     const QList<QUrl> urls = selectedItems().urlList();
0903     if (urls.isEmpty()) {
0904         KMessageBox::information(this, i18n("You did not select a file to trash."), i18n("Nothing to Trash"));
0905         return;
0906     }
0907 
0908     using Iface = KIO::AskUserActionInterface;
0909     auto *trashJob = new KIO::DeleteOrTrashJob(urls, Iface::Trash, Iface::DefaultConfirmation, this);
0910     trashJob->start();
0911 }
0912 
0913 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 76)
0914 void KDirOperator::setIconsZoom(int _value)
0915 {
0916     int value = _value;
0917     value = qMin(100, value);
0918     value = qMax(0, value);
0919     const int stepSize = (KIconLoader::SizeEnormous - KIconLoader::SizeSmall) / 100;
0920     const int val = (value * stepSize) + KIconLoader::SizeSmall;
0921     setIconSize(val);
0922 }
0923 #endif
0924 
0925 void KDirOperator::setIconSize(int value)
0926 {
0927     if (d->m_iconSize == value) {
0928         return;
0929     }
0930 
0931     int size = value;
0932     // Keep size range in sync with KFileWidgetPrivate::m_stdIconSizes
0933     size = std::min(512, size);
0934     size = std::max<int>(KIconLoader::SizeSmall, size);
0935 
0936     d->m_iconSize = size;
0937 
0938     if (!d->m_previewGenerator) {
0939         return;
0940     }
0941 
0942     d->m_itemView->setIconSize(QSize(size, size));
0943     d->m_previewGenerator->updateIcons();
0944 
0945     Q_EMIT currentIconSizeChanged(size);
0946 }
0947 
0948 void KDirOperator::close()
0949 {
0950     resetCursor();
0951     d->m_pendingMimeTypes.clear();
0952     d->m_completion.clear();
0953     d->m_dirCompletion.clear();
0954     d->m_completeListDirty = true;
0955     d->m_dirLister->stop();
0956 }
0957 
0958 void KDirOperator::setUrl(const QUrl &_newurl, bool clearforward)
0959 {
0960     QUrl newurl = _newurl.isValid() ? _newurl.adjusted(QUrl::NormalizePathSegments) : QUrl::fromLocalFile(QDir::homePath());
0961     Utils::appendSlashToPath(newurl);
0962 
0963     // already set
0964     if (newurl.matches(d->m_currUrl, QUrl::StripTrailingSlash)) {
0965         return;
0966     }
0967 
0968     if (!d->isSchemeSupported(newurl.scheme())) {
0969         return;
0970     }
0971 
0972     if (!d->isReadable(newurl)) {
0973         // maybe newurl is a file? check its parent directory
0974         newurl = newurl.adjusted(QUrl::StripTrailingSlash).adjusted(QUrl::RemoveFilename);
0975         if (newurl.matches(d->m_currUrl, QUrl::StripTrailingSlash)) {
0976             Q_EMIT urlEntered(newurl); // To remove the filename in pathCombo
0977             return; // parent is current dir, nothing to do (fixes #173454, too)
0978         }
0979         KIO::StatJob *job = KIO::stat(newurl);
0980         KJobWidgets::setWindow(job, this);
0981         bool res = job->exec();
0982 
0983         KIO::UDSEntry entry = job->statResult();
0984         KFileItem i(entry, newurl);
0985         if ((!res || !d->isReadable(newurl)) && i.isDir()) {
0986             resetCursor();
0987             KMessageBox::error(d->m_itemView,
0988                                i18n("The specified folder does not exist "
0989                                     "or was not readable."));
0990             return;
0991         } else if (!i.isDir()) {
0992             return;
0993         }
0994     }
0995 
0996     if (clearforward) {
0997         // autodelete should remove this one
0998         d->m_backStack.push(new QUrl(d->m_currUrl));
0999         qDeleteAll(d->m_forwardStack);
1000         d->m_forwardStack.clear();
1001     }
1002 
1003     d->m_currUrl = newurl;
1004 
1005     pathChanged();
1006     Q_EMIT urlEntered(newurl);
1007 
1008     // enable/disable actions
1009     QAction *forwardAction = action(KDirOperator::Forward);
1010     forwardAction->setEnabled(!d->m_forwardStack.isEmpty());
1011 
1012     QAction *backAction = action(KDirOperator::Back);
1013     backAction->setEnabled(!d->m_backStack.isEmpty());
1014 
1015     QAction *upAction = action(KDirOperator::Up);
1016     upAction->setEnabled(!isRoot());
1017 
1018     d->openUrl(newurl);
1019 }
1020 
1021 void KDirOperator::updateDir()
1022 {
1023     QApplication::setOverrideCursor(Qt::WaitCursor);
1024     d->m_dirLister->emitChanges();
1025     QApplication::restoreOverrideCursor();
1026 }
1027 
1028 void KDirOperator::rereadDir()
1029 {
1030     pathChanged();
1031     d->openUrl(d->m_currUrl, KDirLister::Reload);
1032 }
1033 
1034 bool KDirOperatorPrivate::isSchemeSupported(const QString &scheme) const
1035 {
1036     return m_supportedSchemes.isEmpty() || m_supportedSchemes.contains(scheme);
1037 }
1038 
1039 bool KDirOperatorPrivate::openUrl(const QUrl &url, KDirLister::OpenUrlFlags flags)
1040 {
1041     const bool result = KProtocolManager::supportsListing(url) && isSchemeSupported(url.scheme()) && m_dirLister->openUrl(url, flags);
1042     if (!result) { // in that case, neither completed() nor canceled() will be emitted by KDL
1043         slotCanceled();
1044     }
1045 
1046     return result;
1047 }
1048 
1049 int KDirOperatorPrivate::sortColumn() const
1050 {
1051     int column = KDirModel::Name;
1052     if (KFile::isSortByDate(m_sorting)) {
1053         column = KDirModel::ModifiedTime;
1054     } else if (KFile::isSortBySize(m_sorting)) {
1055         column = KDirModel::Size;
1056     } else if (KFile::isSortByType(m_sorting)) {
1057         column = KDirModel::Type;
1058     } else {
1059         Q_ASSERT(KFile::isSortByName(m_sorting));
1060     }
1061 
1062     return column;
1063 }
1064 
1065 Qt::SortOrder KDirOperatorPrivate::sortOrder() const
1066 {
1067     return (m_sorting & QDir::Reversed) ? Qt::DescendingOrder : Qt::AscendingOrder;
1068 }
1069 
1070 void KDirOperatorPrivate::updateSorting(QDir::SortFlags sort)
1071 {
1072     // qDebug() << "changing sort flags from"  << m_sorting << "to" << sort;
1073     if (sort == m_sorting) {
1074         return;
1075     }
1076 
1077     m_sorting = sort;
1078     q->updateSortActions();
1079 
1080     m_proxyModel->setSortFoldersFirst(m_sorting & QDir::DirsFirst);
1081     m_proxyModel->sort(sortColumn(), sortOrder());
1082 
1083     // TODO: The headers from QTreeView don't take care about a sorting
1084     // change of the proxy model hence they must be updated the manually.
1085     // This is done here by a qobject_cast, but it would be nicer to:
1086     // - provide a signal 'sortingChanged()'
1087     // - connect KDirOperatorDetailView() with this signal and update the
1088     //   header internally
1089     QTreeView *treeView = qobject_cast<QTreeView *>(m_itemView);
1090     if (treeView != nullptr) {
1091         QHeaderView *headerView = treeView->header();
1092         headerView->blockSignals(true);
1093         headerView->setSortIndicator(sortColumn(), sortOrder());
1094         headerView->blockSignals(false);
1095     }
1096 
1097     assureVisibleSelection();
1098 }
1099 
1100 // Protected
1101 void KDirOperator::pathChanged()
1102 {
1103     if (d->m_itemView == nullptr) {
1104         return;
1105     }
1106 
1107     d->m_pendingMimeTypes.clear();
1108     // d->fileView->clear(); TODO
1109     d->m_completion.clear();
1110     d->m_dirCompletion.clear();
1111 
1112     // it may be, that we weren't ready at this time
1113     QApplication::restoreOverrideCursor();
1114 
1115     // when KIO::Job emits finished, the slot will restore the cursor
1116     QApplication::setOverrideCursor(Qt::WaitCursor);
1117 
1118     if (!d->isReadable(d->m_currUrl)) {
1119         KMessageBox::error(d->m_itemView,
1120                            i18n("The specified folder does not exist "
1121                                 "or was not readable."));
1122         if (d->m_backStack.isEmpty()) {
1123             home();
1124         } else {
1125             back();
1126         }
1127     }
1128 }
1129 
1130 void KDirOperatorPrivate::slotRedirected(const QUrl &newURL)
1131 {
1132     m_currUrl = newURL;
1133     m_pendingMimeTypes.clear();
1134     m_completion.clear();
1135     m_dirCompletion.clear();
1136     m_completeListDirty = true;
1137     Q_EMIT q->urlEntered(newURL);
1138 }
1139 
1140 // Code pinched from kfm then hacked
1141 void KDirOperator::back()
1142 {
1143     if (d->m_backStack.isEmpty()) {
1144         return;
1145     }
1146 
1147     d->m_forwardStack.push(new QUrl(d->m_currUrl));
1148 
1149     QUrl *s = d->m_backStack.pop();
1150     const QUrl newUrl = *s;
1151     delete s;
1152 
1153     if (d->m_dirHighlighting) {
1154         const QUrl _url = newUrl.adjusted(QUrl::StripTrailingSlash).adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash);
1155 
1156         if (_url == d->m_currUrl.adjusted(QUrl::StripTrailingSlash) && !d->m_backStack.isEmpty()) {
1157             // e.g. started in a/b/c, cdUp() twice to "a", then back(), we highlight "c"
1158             d->m_lastUrl = *(d->m_backStack.top());
1159         } else {
1160             d->m_lastUrl = d->m_currUrl;
1161         }
1162     }
1163 
1164     setUrl(newUrl, false);
1165 }
1166 
1167 // Code pinched from kfm then hacked
1168 void KDirOperator::forward()
1169 {
1170     if (d->m_forwardStack.isEmpty()) {
1171         return;
1172     }
1173 
1174     d->m_backStack.push(new QUrl(d->m_currUrl));
1175 
1176     QUrl *s = d->m_forwardStack.pop();
1177     setUrl(*s, false);
1178     delete s;
1179 }
1180 
1181 QUrl KDirOperator::url() const
1182 {
1183     return d->m_currUrl;
1184 }
1185 
1186 void KDirOperator::cdUp()
1187 {
1188     // Allow /d/c// to go up to /d/ instead of /d/c/
1189     QUrl tmp(d->m_currUrl.adjusted(QUrl::NormalizePathSegments));
1190 
1191     if (d->m_dirHighlighting) {
1192         d->m_lastUrl = d->m_currUrl;
1193     }
1194 
1195     setUrl(tmp.resolved(QUrl(QStringLiteral(".."))), true);
1196 }
1197 
1198 void KDirOperator::home()
1199 {
1200     setUrl(QUrl::fromLocalFile(QDir::homePath()), true);
1201 }
1202 
1203 void KDirOperator::clearFilter()
1204 {
1205     d->m_dirLister->setNameFilter(QString());
1206     d->m_dirLister->clearMimeFilter();
1207     checkPreviewSupport();
1208 }
1209 
1210 void KDirOperator::setNameFilter(const QString &filter)
1211 {
1212     d->m_dirLister->setNameFilter(filter);
1213     checkPreviewSupport();
1214 }
1215 
1216 QString KDirOperator::nameFilter() const
1217 {
1218     return d->m_dirLister->nameFilter();
1219 }
1220 
1221 void KDirOperator::setMimeFilter(const QStringList &mimetypes)
1222 {
1223     d->m_dirLister->setMimeFilter(mimetypes);
1224     checkPreviewSupport();
1225 }
1226 
1227 QStringList KDirOperator::mimeFilter() const
1228 {
1229     return d->m_dirLister->mimeFilters();
1230 }
1231 
1232 void KDirOperator::setNewFileMenuSupportedMimeTypes(const QStringList &mimeTypes)
1233 {
1234     d->m_newFileMenu->setSupportedMimeTypes(mimeTypes);
1235 }
1236 
1237 QStringList KDirOperator::newFileMenuSupportedMimeTypes() const
1238 {
1239     return d->m_newFileMenu->supportedMimeTypes();
1240 }
1241 
1242 void KDirOperator::setNewFileMenuSelectDirWhenAlreadyExist(bool selectOnDirExists)
1243 {
1244     d->m_newFileMenu->setSelectDirWhenAlreadyExist(selectOnDirExists);
1245 }
1246 
1247 bool KDirOperator::checkPreviewSupport()
1248 {
1249     KToggleAction *previewAction = static_cast<KToggleAction *>(action(KDirOperator::ShowPreviewPanel));
1250 
1251     bool hasPreviewSupport = false;
1252     KConfigGroup cg(KSharedConfig::openConfig(), ConfigGroup);
1253     if (cg.readEntry("Show Default Preview", true)) {
1254         hasPreviewSupport = d->checkPreviewInternal();
1255     }
1256 
1257     previewAction->setEnabled(hasPreviewSupport);
1258     return hasPreviewSupport;
1259 }
1260 
1261 void KDirOperator::activatedMenu(const KFileItem &item, const QPoint &pos)
1262 {
1263     updateSelectionDependentActions();
1264 
1265     d->m_newFileMenu->setWorkingDirectory(item.url());
1266     d->m_newFileMenu->checkUpToDate();
1267 
1268     action(KDirOperator::New)->setEnabled(item.isDir());
1269 
1270     Q_EMIT contextMenuAboutToShow(item, d->m_actionMenu->menu());
1271 
1272     // Must be right before we call QMenu::exec(), otherwise we might remove
1273     // other non-related actions along with the open-with ones
1274     const QList<QAction *> openWithActions = d->insertOpenWithActions();
1275 
1276     d->m_actionMenu->menu()->exec(pos);
1277 
1278     // Remove the open-with actions, otherwise they would accumulate in the menu
1279     for (auto *action : openWithActions) {
1280         d->m_actionMenu->menu()->removeAction(action);
1281     }
1282 }
1283 
1284 QList<QAction *> KDirOperatorPrivate::insertOpenWithActions()
1285 {
1286     if (!m_showOpenWithActions) {
1287         return {};
1288     }
1289 
1290     const QList<QAction *> beforeOpenWith = m_actionMenu->menu()->actions();
1291 
1292     const KFileItemList items = q->selectedItems();
1293     if (!items.isEmpty()) {
1294         m_itemActions->setItemListProperties(KFileItemListProperties(items));
1295         const QList<QAction *> actions = m_actionMenu->menu()->actions();
1296         QAction *before = !actions.isEmpty() ? actions.at(0) : nullptr;
1297         m_itemActions->insertOpenWithActionsTo(before, m_actionMenu->menu(), QStringList());
1298     }
1299 
1300     // Get the list of the added open-with actions
1301     QList<QAction *> toRemove = m_actionMenu->menu()->actions();
1302     auto it = std::remove_if(toRemove.begin(), toRemove.end(), [beforeOpenWith](QAction *a) {
1303         return beforeOpenWith.contains(a);
1304     });
1305     toRemove.erase(it, toRemove.end());
1306 
1307     return toRemove;
1308 }
1309 
1310 void KDirOperator::showOpenWithActions(bool enable)
1311 {
1312     d->m_showOpenWithActions = enable;
1313 }
1314 
1315 void KDirOperator::changeEvent(QEvent *event)
1316 {
1317     QWidget::changeEvent(event);
1318 }
1319 
1320 bool KDirOperator::eventFilter(QObject *watched, QEvent *event)
1321 {
1322     // If we are not hovering any items, check if there is a current index
1323     // set. In that case, we show the preview of that item.
1324     switch (event->type()) {
1325     case QEvent::MouseMove: {
1326         if (d->m_preview && !d->m_preview->isHidden()) {
1327             const QModelIndex hoveredIndex = d->m_itemView->indexAt(d->m_itemView->viewport()->mapFromGlobal(QCursor::pos()));
1328 
1329             if (d->m_lastHoveredIndex == hoveredIndex) {
1330                 return QWidget::eventFilter(watched, event);
1331             }
1332 
1333             d->m_lastHoveredIndex = hoveredIndex;
1334 
1335             const QModelIndex currentIndex = d->m_itemView->selectionModel() ? d->m_itemView->selectionModel()->currentIndex() : QModelIndex();
1336 
1337             if (!hoveredIndex.isValid() && currentIndex.isValid() && (d->m_lastHoveredIndex != currentIndex)) {
1338                 const KFileItem item = d->m_itemView->model()->data(currentIndex, KDirModel::FileItemRole).value<KFileItem>();
1339                 if (!item.isNull()) {
1340                     d->m_preview->showPreview(item.url());
1341                 }
1342             }
1343         }
1344         break;
1345     }
1346     case QEvent::MouseButtonRelease: {
1347         if (d->m_preview != nullptr && !d->m_preview->isHidden()) {
1348             const QModelIndex hoveredIndex = d->m_itemView->indexAt(d->m_itemView->viewport()->mapFromGlobal(QCursor::pos()));
1349             const QModelIndex focusedIndex = d->m_itemView->selectionModel() ? d->m_itemView->selectionModel()->currentIndex() : QModelIndex();
1350 
1351             if (((!focusedIndex.isValid()) || !d->m_itemView->selectionModel()->isSelected(focusedIndex)) && (!hoveredIndex.isValid())) {
1352                 d->m_preview->clearPreview();
1353             }
1354         }
1355         QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
1356         if (mouseEvent) {
1357             switch (mouseEvent->button()) {
1358             case Qt::BackButton:
1359                 back();
1360                 break;
1361             case Qt::ForwardButton:
1362                 forward();
1363                 break;
1364             default:
1365                 break;
1366             }
1367         }
1368         break;
1369     }
1370     case QEvent::Wheel: {
1371         QWheelEvent *evt = static_cast<QWheelEvent *>(event);
1372         if (evt->modifiers() & Qt::ControlModifier) {
1373             if (evt->angleDelta().y() > 0) {
1374                 setIconSize(d->m_iconSize + 10);
1375             } else {
1376                 setIconSize(d->m_iconSize - 10);
1377             }
1378             return true;
1379         }
1380         break;
1381     }
1382     case QEvent::DragEnter: {
1383         // Accepts drops of one file or folder only
1384         QDragEnterEvent *evt = static_cast<QDragEnterEvent *>(event);
1385         const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(evt->mimeData(), KUrlMimeData::DecodeOptions::PreferLocalUrls);
1386 
1387         // only one file/folder can be dropped at the moment
1388         if (urls.size() != 1) {
1389             evt->ignore();
1390 
1391         } else {
1392             // MIME type filtering
1393             bool mimeFilterPass = true;
1394             const QStringList mimeFilters = d->m_dirLister->mimeFilters();
1395 
1396             if (mimeFilters.size() > 1) {
1397                 mimeFilterPass = false;
1398                 const QUrl &url = urls.constFirst();
1399 
1400                 QMimeDatabase mimeDataBase;
1401                 QMimeType fileMimeType = mimeDataBase.mimeTypeForUrl(url);
1402 
1403                 QRegularExpression regex;
1404                 for (const auto &mimeFilter : mimeFilters) {
1405                     regex.setPattern(mimeFilter);
1406                     if (regex.match(fileMimeType.name()).hasMatch()) { // matches!
1407                         mimeFilterPass = true;
1408                         break;
1409                     }
1410                 }
1411             }
1412 
1413             event->setAccepted(mimeFilterPass);
1414         }
1415 
1416         return true;
1417     }
1418     case QEvent::Drop: {
1419         QDropEvent *evt = static_cast<QDropEvent *>(event);
1420         const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(evt->mimeData(), KUrlMimeData::DecodeOptions::PreferLocalUrls);
1421 
1422         const QUrl &url = urls.constFirst();
1423 
1424         // stat the url to get details
1425         KIO::StatJob *job = KIO::stat(url, KIO::HideProgressInfo);
1426         job->exec();
1427 
1428         setFocus();
1429 
1430         const KIO::UDSEntry entry = job->statResult();
1431 
1432         if (entry.isDir()) {
1433             // if this was a directory
1434             setUrl(url, false);
1435         } else {
1436             // if the current url is not known
1437             if (d->m_dirLister->findByUrl(url).isNull()) {
1438                 setUrl(url.adjusted(QUrl::RemoveFilename), false);
1439 
1440                 // Will set the current item once loading has finished
1441                 auto urlSetterClosure = [this, url]() {
1442                     setCurrentItem(url);
1443                     QObject::disconnect(d->m_connection);
1444                 };
1445                 d->m_connection = connect(this, &KDirOperator::finishedLoading, this, urlSetterClosure);
1446             } else {
1447                 setCurrentItem(url);
1448             }
1449         }
1450         evt->accept();
1451         return true;
1452     }
1453     case QEvent::KeyPress: {
1454         QKeyEvent *evt = static_cast<QKeyEvent *>(event);
1455         if (evt->key() == Qt::Key_Return || evt->key() == Qt::Key_Enter) {
1456             // when no elements are selected and Return/Enter is pressed
1457             // emit keyEnterReturnPressed
1458             // let activated event be emitted by subsequent QAbstractItemView::keyPress otherwise
1459             if (!d->m_itemView->currentIndex().isValid()) {
1460                 Q_EMIT keyEnterReturnPressed();
1461                 evt->accept();
1462                 return true;
1463             }
1464         }
1465         break;
1466     }
1467     case QEvent::Resize: {
1468         /* clang-format off */
1469         if (watched == d->m_itemView->viewport()
1470             && d->m_itemView->horizontalScrollBar()
1471             && d->m_progressBar->parent() == this /* it could have been reparented to a statusbar */) { /* clang-format on */
1472             if (d->m_itemView->horizontalScrollBar()->isVisible()) {
1473                 // Show the progress bar above the horizontal scrollbar that may be visible
1474                 // in compact view
1475                 QPoint progressBarPos = d->progressBarPos();
1476                 progressBarPos.ry() -= d->m_itemView->horizontalScrollBar()->height();
1477                 d->m_progressBar->move(progressBarPos);
1478             } else {
1479                 d->m_progressBar->move(d->progressBarPos());
1480             }
1481         }
1482         break;
1483     }
1484     default:
1485         break;
1486     }
1487 
1488     return QWidget::eventFilter(watched, event);
1489 }
1490 
1491 bool KDirOperatorPrivate::checkPreviewInternal() const
1492 {
1493     const QStringList supported = KIO::PreviewJob::supportedMimeTypes();
1494     // no preview support for directories?
1495     if (q->dirOnlyMode() && !supported.contains(QLatin1String("inode/directory"))) {
1496         return false;
1497     }
1498 
1499     const QStringList mimeTypes = m_dirLister->mimeFilters();
1500     const QStringList nameFilters = m_dirLister->nameFilter().split(QLatin1Char(' '), Qt::SkipEmptyParts);
1501 
1502     if (mimeTypes.isEmpty() && nameFilters.isEmpty() && !supported.isEmpty()) {
1503         return true;
1504     } else {
1505         QMimeDatabase db;
1506         QRegularExpression re;
1507 
1508         if (!mimeTypes.isEmpty()) {
1509             for (const QString &str : supported) {
1510                 // wildcard matching because the "mimetype" can be "image/*"
1511                 re.setPattern(QRegularExpression::wildcardToRegularExpression(str));
1512 
1513                 if (mimeTypes.indexOf(re) != -1) { // matches! -> we want previews
1514                     return true;
1515                 }
1516             }
1517         }
1518 
1519         if (!nameFilters.isEmpty()) {
1520             // find the MIME types of all the filter-patterns
1521             for (const QString &filter : nameFilters) {
1522                 if (filter == QLatin1Char('*')) {
1523                     return true;
1524                 }
1525 
1526                 const QMimeType mt = db.mimeTypeForFile(filter, QMimeDatabase::MatchExtension /*fast mode, no file contents exist*/);
1527                 if (!mt.isValid()) {
1528                     continue;
1529                 }
1530                 const QString mime = mt.name();
1531 
1532                 for (const QString &str : supported) {
1533                     // the "mimetypes" we get from the PreviewJob can be "image/*"
1534                     // so we need to check in wildcard mode
1535                     re.setPattern(QRegularExpression::wildcardToRegularExpression(str));
1536                     if (re.match(mime).hasMatch()) {
1537                         return true;
1538                     }
1539                 }
1540             }
1541         }
1542     }
1543 
1544     return false;
1545 }
1546 
1547 QAbstractItemView *KDirOperator::createView(QWidget *parent, KFile::FileView viewKind)
1548 {
1549     QAbstractItemView *itemView = nullptr;
1550     if (KFile::isDetailView(viewKind) || KFile::isTreeView(viewKind) || KFile::isDetailTreeView(viewKind)) {
1551         KDirOperatorDetailView *detailView = new KDirOperatorDetailView(parent);
1552         detailView->setViewMode(viewKind);
1553         itemView = detailView;
1554     } else {
1555         itemView = new KDirOperatorIconView(parent, decorationPosition());
1556     }
1557 
1558     return itemView;
1559 }
1560 
1561 void KDirOperator::setAcceptDrops(bool acceptsDrops)
1562 {
1563     QWidget::setAcceptDrops(acceptsDrops);
1564     if (view()) {
1565         view()->setAcceptDrops(acceptsDrops);
1566         if (acceptsDrops) {
1567             view()->installEventFilter(this);
1568         } else {
1569             view()->removeEventFilter(this);
1570         }
1571     }
1572 }
1573 
1574 void KDirOperator::setDropOptions(int options)
1575 {
1576     d->m_dropOptions = options;
1577     // TODO:
1578     // if (d->fileView)
1579     //   d->fileView->setDropOptions(options);
1580 }
1581 
1582 void KDirOperator::setViewMode(KFile::FileView viewKind)
1583 {
1584     bool preview = (KFile::isPreviewInfo(viewKind) || KFile::isPreviewContents(viewKind));
1585 
1586     if (viewKind == KFile::Default) {
1587         if (KFile::isDetailView((KFile::FileView)d->m_defaultView)) {
1588             viewKind = KFile::Detail;
1589         } else if (KFile::isTreeView((KFile::FileView)d->m_defaultView)) {
1590             viewKind = KFile::Tree;
1591         } else if (KFile::isDetailTreeView((KFile::FileView)d->m_defaultView)) {
1592             viewKind = KFile::DetailTree;
1593         } else {
1594             viewKind = KFile::Simple;
1595         }
1596 
1597         const KFile::FileView defaultViewKind = static_cast<KFile::FileView>(d->m_defaultView);
1598         preview = (KFile::isPreviewInfo(defaultViewKind) || KFile::isPreviewContents(defaultViewKind)) && action(KDirOperator::ShowPreviewPanel)->isEnabled();
1599     }
1600 
1601     d->m_viewKind = static_cast<int>(viewKind);
1602     viewKind = static_cast<KFile::FileView>(d->m_viewKind);
1603 
1604     QAbstractItemView *newView = createView(this, viewKind);
1605     setViewInternal(newView);
1606 
1607     if (acceptDrops()) {
1608         newView->setAcceptDrops(true);
1609         newView->installEventFilter(this);
1610     }
1611 
1612     d->togglePreview(preview);
1613 }
1614 
1615 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
1616 void KDirOperator::setView(KFile::FileView viewKind)
1617 {
1618     setViewMode(viewKind);
1619 }
1620 #endif
1621 
1622 KFile::FileView KDirOperator::viewMode() const
1623 {
1624     return static_cast<KFile::FileView>(d->m_viewKind);
1625 }
1626 
1627 QAbstractItemView *KDirOperator::view() const
1628 {
1629     return d->m_itemView;
1630 }
1631 
1632 KFile::Modes KDirOperator::mode() const
1633 {
1634     return d->m_mode;
1635 }
1636 
1637 void KDirOperator::setMode(KFile::Modes mode)
1638 {
1639     if (d->m_mode == mode) {
1640         return;
1641     }
1642 
1643     const bool isDirOnlyChanged = dirOnlyMode(d->m_mode) != dirOnlyMode(mode);
1644 
1645     d->m_mode = mode;
1646 
1647     d->m_dirLister->setDirOnlyMode(dirOnlyMode());
1648 
1649     // When KFile::Directory mode changes, we need to update the dir,
1650     // otherwise initially we would be showing dirs and files even when
1651     // dirOnlyMode() is true
1652     if (isDirOnlyChanged) {
1653         updateDir();
1654     }
1655 
1656     // reset the view with the different mode
1657     if (d->m_itemView != nullptr) {
1658         setViewMode(static_cast<KFile::FileView>(d->m_viewKind));
1659     }
1660 }
1661 
1662 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
1663 void KDirOperator::setView(QAbstractItemView *view)
1664 {
1665     setViewInternal(view);
1666 }
1667 #endif
1668 
1669 void KDirOperator::setViewInternal(QAbstractItemView *view)
1670 {
1671     if (view == d->m_itemView) {
1672         return;
1673     }
1674 
1675     // TODO: do a real timer and restart it after that
1676     d->m_pendingMimeTypes.clear();
1677     const bool listDir = (d->m_itemView == nullptr);
1678 
1679     if (d->m_mode & KFile::Files) {
1680         view->setSelectionMode(QAbstractItemView::ExtendedSelection);
1681     } else {
1682         view->setSelectionMode(QAbstractItemView::SingleSelection);
1683     }
1684 
1685     QItemSelectionModel *selectionModel = nullptr;
1686     if ((d->m_itemView != nullptr) && d->m_itemView->selectionModel()->hasSelection()) {
1687         // remember the selection of the current item view and apply this selection
1688         // to the new view later
1689         const QItemSelection selection = d->m_itemView->selectionModel()->selection();
1690         selectionModel = new QItemSelectionModel(d->m_proxyModel, this);
1691         selectionModel->select(selection, QItemSelectionModel::Select);
1692     }
1693 
1694     setFocusProxy(nullptr);
1695     delete d->m_itemView;
1696     d->m_itemView = view;
1697     d->m_itemView->setModel(d->m_proxyModel);
1698     setFocusProxy(d->m_itemView);
1699 
1700     d->m_itemView->viewport()->setObjectName(QStringLiteral("d->itemview_viewport"));
1701     view->viewport()->installEventFilter(this);
1702 
1703     KFileItemDelegate *delegate = new KFileItemDelegate(d->m_itemView);
1704     d->m_itemView->setItemDelegate(delegate);
1705     d->m_itemView->viewport()->setAttribute(Qt::WA_Hover);
1706     d->m_itemView->setContextMenuPolicy(Qt::CustomContextMenu);
1707     d->m_itemView->setMouseTracking(true);
1708     // d->itemView->setDropOptions(d->dropOptions);
1709 
1710     // first push our settings to the view, then listen for changes from the view
1711     QTreeView *treeView = qobject_cast<QTreeView *>(d->m_itemView);
1712     if (treeView) {
1713         QHeaderView *headerView = treeView->header();
1714         headerView->setSortIndicator(d->sortColumn(), d->sortOrder());
1715         connect(headerView, &QHeaderView::sortIndicatorChanged, this, [this](int logicalIndex, Qt::SortOrder order) {
1716             d->synchronizeSortingState(logicalIndex, order);
1717         });
1718     }
1719 
1720     connect(d->m_itemView, &QAbstractItemView::activated, this, [this](QModelIndex index) {
1721         d->slotActivated(index);
1722     });
1723 
1724     connect(d->m_itemView, &QAbstractItemView::customContextMenuRequested, this, [this](QPoint pos) {
1725         d->openContextMenu(pos);
1726     });
1727 
1728     connect(d->m_itemView, &QAbstractItemView::entered, this, [this](QModelIndex index) {
1729         d->triggerPreview(index);
1730     });
1731 
1732     d->m_splitter->insertWidget(0, d->m_itemView);
1733 
1734     d->m_splitter->resize(size());
1735     d->m_itemView->show();
1736 
1737     if (listDir) {
1738         QApplication::setOverrideCursor(Qt::WaitCursor);
1739         d->openUrl(d->m_currUrl);
1740     }
1741 
1742     if (selectionModel != nullptr) {
1743         d->m_itemView->setSelectionModel(selectionModel);
1744         auto assureVisFunc = [this]() {
1745             d->assureVisibleSelection();
1746         };
1747         QMetaObject::invokeMethod(this, assureVisFunc, Qt::QueuedConnection);
1748     }
1749 
1750     connect(d->m_itemView->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](QModelIndex index) {
1751         d->triggerPreview(index);
1752     });
1753     connect(d->m_itemView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this]() {
1754         d->slotSelectionChanged();
1755     });
1756 
1757     // if we cannot cast it to a QListView, disable the "Icon Position" menu. Note that this check
1758     // needs to be done here, and not in createView, since we can be set an external view
1759     d->m_decorationMenu->setEnabled(qobject_cast<QListView *>(d->m_itemView));
1760 
1761     d->m_shouldFetchForItems = qobject_cast<QTreeView *>(view);
1762     if (d->m_shouldFetchForItems) {
1763         connect(d->m_dirModel, &KDirModel::expand, this, [this](QModelIndex index) {
1764             d->slotExpandToUrl(index);
1765         });
1766     } else {
1767         d->m_itemsToBeSetAsCurrent.clear();
1768     }
1769 
1770     const bool previewForcedToTrue = d->m_inlinePreviewState == KDirOperatorPrivate::ForcedToTrue;
1771     const bool previewShown = d->m_inlinePreviewState == KDirOperatorPrivate::NotForced ? d->m_showPreviews : previewForcedToTrue;
1772     d->m_previewGenerator = new KFilePreviewGenerator(d->m_itemView);
1773     d->m_itemView->setIconSize(previewForcedToTrue ? QSize(KIconLoader::SizeHuge, KIconLoader::SizeHuge) : QSize(d->m_iconSize, d->m_iconSize));
1774     d->m_previewGenerator->setPreviewShown(previewShown);
1775     action(KDirOperator::ShowPreview)->setChecked(previewShown);
1776 
1777     // ensure we change everything needed
1778     d->slotChangeDecorationPosition();
1779     updateViewActions();
1780 
1781     Q_EMIT viewChanged(view);
1782 
1783     const int zoom = previewForcedToTrue ? KIconLoader::SizeHuge : d->iconSizeForViewType(view);
1784 
1785     // this will make d->m_iconSize be updated, since setIconSize slot will be called
1786     Q_EMIT currentIconSizeChanged(zoom);
1787 }
1788 
1789 void KDirOperator::setDirLister(KDirLister *lister)
1790 {
1791     if (lister == d->m_dirLister) { // sanity check
1792         return;
1793     }
1794 
1795     delete d->m_dirModel;
1796     d->m_dirModel = nullptr;
1797 
1798     delete d->m_proxyModel;
1799     d->m_proxyModel = nullptr;
1800 
1801     // delete d->m_dirLister; // deleted by KDirModel already, which took ownership
1802     d->m_dirLister = lister;
1803 
1804     d->m_dirModel = new KDirModel(this);
1805     d->m_dirModel->setDirLister(d->m_dirLister);
1806     d->m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory);
1807 
1808     d->m_shouldFetchForItems = qobject_cast<QTreeView *>(d->m_itemView);
1809     if (d->m_shouldFetchForItems) {
1810         connect(d->m_dirModel, &KDirModel::expand, this, [this](QModelIndex index) {
1811             d->slotExpandToUrl(index);
1812         });
1813     } else {
1814         d->m_itemsToBeSetAsCurrent.clear();
1815     }
1816 
1817     d->m_proxyModel = new KDirSortFilterProxyModel(this);
1818     d->m_proxyModel->setSourceModel(d->m_dirModel);
1819 
1820     d->m_dirLister->setDelayedMimeTypes(true);
1821 
1822     QWidget *mainWidget = topLevelWidget();
1823     d->m_dirLister->setMainWindow(mainWidget);
1824     // qDebug() << "mainWidget=" << mainWidget;
1825 
1826     connect(d->m_dirLister, &KCoreDirLister::percent, this, [this](int percent) {
1827         d->slotProgress(percent);
1828     });
1829     connect(d->m_dirLister, &KCoreDirLister::started, this, [this]() {
1830         d->slotStarted();
1831     });
1832     connect(d->m_dirLister, qOverload<>(&KCoreDirLister::completed), this, [this]() {
1833         d->slotIOFinished();
1834     });
1835     connect(d->m_dirLister, qOverload<>(&KCoreDirLister::canceled), this, [this]() {
1836         d->slotCanceled();
1837     });
1838     connect(d->m_dirLister, &KCoreDirLister::jobError, this, [this]() {
1839         d->slotIOFinished();
1840     });
1841     connect(d->m_dirLister, qOverload<const QUrl &, const QUrl &>(&KCoreDirLister::redirection), this, [this](const QUrl &, const QUrl &newUrl) {
1842         d->slotRedirected(newUrl);
1843     });
1844     connect(d->m_dirLister, &KCoreDirLister::newItems, this, [this]() {
1845         d->slotItemsChanged();
1846     });
1847     connect(d->m_dirLister, &KCoreDirLister::itemsDeleted, this, [this]() {
1848         d->slotItemsChanged();
1849     });
1850     connect(d->m_dirLister, qOverload<>(&KCoreDirLister::clear), this, [this]() {
1851         d->slotItemsChanged();
1852     });
1853 }
1854 
1855 void KDirOperator::selectDir(const KFileItem &item)
1856 {
1857     setUrl(item.targetUrl(), true);
1858 }
1859 
1860 void KDirOperator::selectFile(const KFileItem &item)
1861 {
1862     QApplication::restoreOverrideCursor();
1863 
1864     Q_EMIT fileSelected(item);
1865 }
1866 
1867 void KDirOperator::highlightFile(const KFileItem &item)
1868 {
1869     if ((d->m_preview != nullptr && !d->m_preview->isHidden()) && !item.isNull()) {
1870         d->m_preview->showPreview(item.url());
1871     }
1872 
1873     Q_EMIT fileHighlighted(item);
1874 }
1875 
1876 void KDirOperator::setCurrentItem(const QUrl &url)
1877 {
1878     // qDebug();
1879 
1880     KFileItem item = d->m_dirLister->findByUrl(url);
1881     if (d->m_shouldFetchForItems && item.isNull()) {
1882         d->m_itemsToBeSetAsCurrent << url;
1883 
1884         if (d->m_viewKind == KFile::DetailTree) {
1885             d->m_dirModel->expandToUrl(url);
1886         }
1887 
1888         return;
1889     }
1890 
1891     setCurrentItem(item);
1892 }
1893 
1894 void KDirOperator::setCurrentItem(const KFileItem &item)
1895 {
1896     // qDebug();
1897 
1898     if (!d->m_itemView) {
1899         return;
1900     }
1901 
1902     QItemSelectionModel *selModel = d->m_itemView->selectionModel();
1903     if (selModel) {
1904         selModel->clear();
1905         if (!item.isNull()) {
1906             const QModelIndex dirIndex = d->m_dirModel->indexForItem(item);
1907             const QModelIndex proxyIndex = d->m_proxyModel->mapFromSource(dirIndex);
1908             selModel->setCurrentIndex(proxyIndex, QItemSelectionModel::Select);
1909         }
1910     }
1911 }
1912 
1913 void KDirOperator::setCurrentItems(const QList<QUrl> &urls)
1914 {
1915     // qDebug();
1916 
1917     if (!d->m_itemView) {
1918         return;
1919     }
1920 
1921     KFileItemList itemList;
1922     for (const QUrl &url : urls) {
1923         KFileItem item = d->m_dirLister->findByUrl(url);
1924         if (d->m_shouldFetchForItems && item.isNull()) {
1925             d->m_itemsToBeSetAsCurrent << url;
1926 
1927             if (d->m_viewKind == KFile::DetailTree) {
1928                 d->m_dirModel->expandToUrl(url);
1929             }
1930 
1931             continue;
1932         }
1933 
1934         itemList << item;
1935     }
1936 
1937     setCurrentItems(itemList);
1938 }
1939 
1940 void KDirOperator::setCurrentItems(const KFileItemList &items)
1941 {
1942     // qDebug();
1943 
1944     if (d->m_itemView == nullptr) {
1945         return;
1946     }
1947 
1948     QItemSelectionModel *selModel = d->m_itemView->selectionModel();
1949     if (selModel) {
1950         selModel->clear();
1951         QModelIndex proxyIndex;
1952         for (const KFileItem &item : items) {
1953             if (!item.isNull()) {
1954                 const QModelIndex dirIndex = d->m_dirModel->indexForItem(item);
1955                 proxyIndex = d->m_proxyModel->mapFromSource(dirIndex);
1956                 selModel->select(proxyIndex, QItemSelectionModel::Select);
1957             }
1958         }
1959         if (proxyIndex.isValid()) {
1960             selModel->setCurrentIndex(proxyIndex, QItemSelectionModel::NoUpdate);
1961         }
1962     }
1963 }
1964 
1965 QString KDirOperator::makeCompletion(const QString &string)
1966 {
1967     if (string.isEmpty()) {
1968         d->m_itemView->selectionModel()->clear();
1969         return QString();
1970     }
1971 
1972     prepareCompletionObjects();
1973     return d->m_completion.makeCompletion(string);
1974 }
1975 
1976 QString KDirOperator::makeDirCompletion(const QString &string)
1977 {
1978     if (string.isEmpty()) {
1979         d->m_itemView->selectionModel()->clear();
1980         return QString();
1981     }
1982 
1983     prepareCompletionObjects();
1984     return d->m_dirCompletion.makeCompletion(string);
1985 }
1986 
1987 void KDirOperator::prepareCompletionObjects()
1988 {
1989     if (d->m_itemView == nullptr) {
1990         return;
1991     }
1992 
1993     if (d->m_completeListDirty) { // create the list of all possible completions
1994         const KFileItemList itemList = d->m_dirLister->items();
1995         for (const KFileItem &item : itemList) {
1996             d->m_completion.addItem(item.name());
1997             if (item.isDir()) {
1998                 d->m_dirCompletion.addItem(item.name());
1999             }
2000         }
2001         d->m_completeListDirty = false;
2002     }
2003 }
2004 
2005 void KDirOperator::slotCompletionMatch(const QString &match)
2006 {
2007     QUrl url(match);
2008     if (url.isRelative()) {
2009         url = d->m_currUrl.resolved(url);
2010     }
2011     setCurrentItem(url);
2012     Q_EMIT completion(match);
2013 }
2014 
2015 void KDirOperator::setupActions()
2016 {
2017 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2018     d->m_actionCollection = new KActionCollection(this);
2019     d->m_actionCollection->setObjectName(QStringLiteral("KDirOperator::actionCollection"));
2020 #endif
2021 
2022     d->m_actionMenu = new KActionMenu(i18n("Menu"), this);
2023 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2024     d->m_actionCollection->addAction(QStringLiteral("popupMenu"), d->m_actionMenu);
2025 #endif
2026     d->m_actions[PopupMenu] = d->m_actionMenu;
2027 
2028     QAction *upAction = KStandardAction::create(KStandardAction::Up, this, SLOT(cdUp()), this);
2029 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2030     d->m_actionCollection->addAction(QStringLiteral("up"), upAction);
2031 #endif
2032     d->m_actions[Up] = upAction;
2033     upAction->setText(i18n("Parent Folder"));
2034 
2035     QAction *backAction = KStandardAction::create(KStandardAction::Back, this, SLOT(back()), this);
2036 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2037     d->m_actionCollection->addAction(QStringLiteral("back"), backAction);
2038 #endif
2039     d->m_actions[Back] = backAction;
2040     auto backShortcuts = backAction->shortcuts();
2041     backShortcuts << Qt::Key_Backspace;
2042     backAction->setShortcuts(backShortcuts);
2043     backAction->setToolTip(i18nc("@info", "Go back"));
2044 
2045     QAction *forwardAction = KStandardAction::create(KStandardAction::Forward, this, SLOT(forward()), this);
2046 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2047     d->m_actionCollection->addAction(QStringLiteral("forward"), forwardAction);
2048 #endif
2049     d->m_actions[Forward] = forwardAction;
2050     forwardAction->setToolTip(i18nc("@info", "Go forward"));
2051 
2052     QAction *homeAction = KStandardAction::create(KStandardAction::Home, this, SLOT(home()), this);
2053 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2054     d->m_actionCollection->addAction(QStringLiteral("home"), homeAction);
2055 #endif
2056     d->m_actions[Home] = homeAction;
2057     homeAction->setText(i18n("Home Folder"));
2058 
2059     QAction *reloadAction = KStandardAction::create(KStandardAction::Redisplay, this, SLOT(rereadDir()), this);
2060 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2061     d->m_actionCollection->addAction(QStringLiteral("reload"), reloadAction);
2062 #endif
2063     d->m_actions[Reload] = reloadAction;
2064     reloadAction->setText(i18n("Reload"));
2065     reloadAction->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::Reload));
2066 
2067     QAction *mkdirAction = new QAction(i18n("New Folder..."), this);
2068 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2069     d->m_actionCollection->addAction(QStringLiteral("mkdir"), mkdirAction);
2070 #endif
2071     d->m_actions[NewFolder] = mkdirAction;
2072     mkdirAction->setIcon(QIcon::fromTheme(QStringLiteral("folder-new")));
2073     connect(mkdirAction, &QAction::triggered, this, [this]() {
2074         mkdir();
2075     });
2076 
2077     QAction *rename = KStandardAction::renameFile(this, &KDirOperator::renameSelected, this);
2078     d->m_actions[Rename] = rename;
2079 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2080     d->m_actionCollection->addAction(QStringLiteral("rename"), rename);
2081 #endif
2082 
2083     QAction *trash = new QAction(i18n("Move to Trash"), this);
2084     d->m_actions[Trash] = trash;
2085 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2086     d->m_actionCollection->addAction(QStringLiteral("trash"), trash);
2087 #endif
2088     trash->setIcon(QIcon::fromTheme(QStringLiteral("user-trash")));
2089     trash->setShortcut(Qt::Key_Delete);
2090     connect(trash, &QAction::triggered, this, &KDirOperator::trashSelected);
2091 
2092     QAction *action = new QAction(i18n("Delete"), this);
2093     d->m_actions[Delete] = action;
2094 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2095     d->m_actionCollection->addAction(QStringLiteral("delete"), action);
2096 #endif
2097     action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
2098     action->setShortcut(Qt::SHIFT | Qt::Key_Delete);
2099     connect(action, &QAction::triggered, this, &KDirOperator::deleteSelected);
2100 
2101     // the sort menu actions
2102     KActionMenu *sortMenu = new KActionMenu(i18n("Sorting"), this);
2103     d->m_actions[SortMenu] = sortMenu;
2104     sortMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-sort")));
2105     sortMenu->setPopupMode(QToolButton::InstantPopup);
2106 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2107     d->m_actionCollection->addAction(QStringLiteral("sorting menu"), sortMenu);
2108 #endif
2109 
2110     KToggleAction *byNameAction = new KToggleAction(i18n("Sort by Name"), this);
2111     d->m_actions[SortByName] = byNameAction;
2112 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2113     d->m_actionCollection->addAction(QStringLiteral("by name"), byNameAction);
2114 #endif
2115     connect(byNameAction, &QAction::triggered, this, [this]() {
2116         d->slotSortByName();
2117     });
2118 
2119     KToggleAction *bySizeAction = new KToggleAction(i18n("Sort by Size"), this);
2120     d->m_actions[SortBySize] = bySizeAction;
2121 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2122     d->m_actionCollection->addAction(QStringLiteral("by size"), bySizeAction);
2123 #endif
2124     connect(bySizeAction, &QAction::triggered, this, [this]() {
2125         d->slotSortBySize();
2126     });
2127 
2128     KToggleAction *byDateAction = new KToggleAction(i18n("Sort by Date"), this);
2129     d->m_actions[SortByDate] = byDateAction;
2130 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2131     d->m_actionCollection->addAction(QStringLiteral("by date"), byDateAction);
2132 #endif
2133     connect(byDateAction, &QAction::triggered, this, [this]() {
2134         d->slotSortByDate();
2135     });
2136 
2137     KToggleAction *byTypeAction = new KToggleAction(i18n("Sort by Type"), this);
2138     d->m_actions[SortByType] = byTypeAction;
2139 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2140     d->m_actionCollection->addAction(QStringLiteral("by type"), byTypeAction);
2141 #endif
2142     connect(byTypeAction, &QAction::triggered, this, [this]() {
2143         d->slotSortByType();
2144     });
2145 
2146     QActionGroup *sortOrderGroup = new QActionGroup(this);
2147     sortOrderGroup->setExclusive(true);
2148 
2149     KToggleAction *ascendingAction = new KToggleAction(i18n("Ascending"), this);
2150     d->m_actions[SortAscending] = ascendingAction;
2151 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2152     d->m_actionCollection->addAction(QStringLiteral("ascending"), ascendingAction);
2153 #endif
2154     ascendingAction->setActionGroup(sortOrderGroup);
2155     connect(ascendingAction, &QAction::triggered, this, [this]() {
2156         this->d->slotSortReversed(false);
2157     });
2158 
2159     KToggleAction *descendingAction = new KToggleAction(i18n("Descending"), this);
2160     d->m_actions[SortDescending] = descendingAction;
2161 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2162     d->m_actionCollection->addAction(QStringLiteral("descending"), descendingAction);
2163 #endif
2164     descendingAction->setActionGroup(sortOrderGroup);
2165     connect(descendingAction, &QAction::triggered, this, [this]() {
2166         this->d->slotSortReversed(true);
2167     });
2168 
2169     KToggleAction *dirsFirstAction = new KToggleAction(i18n("Folders First"), this);
2170     d->m_actions[SortFoldersFirst] = dirsFirstAction;
2171 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2172     d->m_actionCollection->addAction(QStringLiteral("dirs first"), dirsFirstAction);
2173 #endif
2174     connect(dirsFirstAction, &QAction::triggered, this, [this]() {
2175         d->slotToggleDirsFirst();
2176     });
2177 
2178     KToggleAction *hiddenFilesLastAction = new KToggleAction(i18n("Hidden Files Last"), this);
2179     d->m_actions[SortHiddenFilesLast] = hiddenFilesLastAction;
2180 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2181     d->m_actionCollection->addAction(QStringLiteral("hidden files last"), hiddenFilesLastAction);
2182 #endif
2183     connect(hiddenFilesLastAction, &QAction::toggled, this, [this](bool checked) {
2184         d->m_proxyModel->setSortHiddenFilesLast(checked);
2185     });
2186 
2187     // View modes that match those of Dolphin
2188     KToggleAction *iconsViewAction = new KToggleAction(i18n("Icons View"), this);
2189     d->m_actions[ViewIconsView] = iconsViewAction;
2190     iconsViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons")));
2191 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2192     d->m_actionCollection->addAction(QStringLiteral("icons view"), iconsViewAction);
2193 #endif
2194     connect(iconsViewAction, &QAction::triggered, this, [this]() {
2195         d->slotIconsView();
2196     });
2197 
2198     KToggleAction *compactViewAction = new KToggleAction(i18n("Compact View"), this);
2199     d->m_actions[ViewCompactView] = compactViewAction;
2200     compactViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details")));
2201 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2202     d->m_actionCollection->addAction(QStringLiteral("compact view"), compactViewAction);
2203 #endif
2204     connect(compactViewAction, &QAction::triggered, this, [this]() {
2205         d->slotCompactView();
2206     });
2207 
2208     KToggleAction *detailsViewAction = new KToggleAction(i18n("Details View"), this);
2209     d->m_actions[ViewDetailsView] = detailsViewAction;
2210     detailsViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
2211 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2212     d->m_actionCollection->addAction(QStringLiteral("details view"), detailsViewAction);
2213 #endif
2214     connect(detailsViewAction, &QAction::triggered, this, [this]() {
2215         d->slotDetailsView();
2216     });
2217 
2218     QActionGroup *viewModeGroup = new QActionGroup(this);
2219     viewModeGroup->setExclusive(true);
2220     iconsViewAction->setActionGroup(viewModeGroup);
2221     compactViewAction->setActionGroup(viewModeGroup);
2222     detailsViewAction->setActionGroup(viewModeGroup);
2223 
2224     QActionGroup *sortGroup = new QActionGroup(this);
2225     byNameAction->setActionGroup(sortGroup);
2226     bySizeAction->setActionGroup(sortGroup);
2227     byDateAction->setActionGroup(sortGroup);
2228     byTypeAction->setActionGroup(sortGroup);
2229 
2230     d->m_decorationMenu = new KActionMenu(i18n("Icon Position"), this);
2231 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2232     d->m_actionCollection->addAction(QStringLiteral("decoration menu"), d->m_decorationMenu);
2233 #endif
2234     d->m_actions[DecorationMenu] = d->m_decorationMenu;
2235 
2236     d->m_leftAction = new KToggleAction(i18n("Next to File Name"), this);
2237 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2238     d->m_actionCollection->addAction(QStringLiteral("decorationAtLeft"), d->m_leftAction);
2239 #endif
2240     d->m_actions[DecorationAtLeft] = d->m_leftAction;
2241     connect(d->m_leftAction, &QAction::triggered, this, [this]() {
2242         d->slotChangeDecorationPosition();
2243     });
2244 
2245     KToggleAction *topAction = new KToggleAction(i18n("Above File Name"), this);
2246 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2247     d->m_actionCollection->addAction(QStringLiteral("decorationAtTop"), topAction);
2248 #endif
2249     d->m_actions[DecorationAtTop] = topAction;
2250     connect(topAction, &QAction::triggered, this, [this]() {
2251         d->slotChangeDecorationPosition();
2252     });
2253 
2254     d->m_decorationMenu->addAction(d->m_leftAction);
2255     d->m_decorationMenu->addAction(topAction);
2256 
2257     QActionGroup *decorationGroup = new QActionGroup(this);
2258     decorationGroup->setExclusive(true);
2259     d->m_leftAction->setActionGroup(decorationGroup);
2260     topAction->setActionGroup(decorationGroup);
2261 
2262     KToggleAction *shortAction = new KToggleAction(i18n("Short View"), this);
2263 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2264     d->m_actionCollection->addAction(QStringLiteral("short view"), shortAction);
2265 #endif
2266     d->m_actions[ShortView] = shortAction;
2267     shortAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons")));
2268     connect(shortAction, &QAction::triggered, this, [this]() {
2269         d->slotSimpleView();
2270     });
2271 
2272     KToggleAction *detailedAction = new KToggleAction(i18n("Detailed View"), this);
2273 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2274     d->m_actionCollection->addAction(QStringLiteral("detailed view"), detailedAction);
2275 #endif
2276     d->m_actions[DetailedView] = detailedAction;
2277     detailedAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details")));
2278     connect(detailedAction, &QAction::triggered, this, [this]() {
2279         d->slotDetailedView();
2280     });
2281 
2282     KToggleAction *treeAction = new KToggleAction(i18n("Tree View"), this);
2283 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2284     d->m_actionCollection->addAction(QStringLiteral("tree view"), treeAction);
2285 #endif
2286     d->m_actions[TreeView] = treeAction;
2287     treeAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
2288     connect(treeAction, &QAction::triggered, this, [this]() {
2289         d->slotTreeView();
2290     });
2291 
2292     KToggleAction *detailedTreeAction = new KToggleAction(i18n("Detailed Tree View"), this);
2293 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2294     d->m_actionCollection->addAction(QStringLiteral("detailed tree view"), detailedTreeAction);
2295 #endif
2296     d->m_actions[DetailedTreeView] = detailedTreeAction;
2297     detailedTreeAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
2298     connect(detailedTreeAction, &QAction::triggered, this, [this]() {
2299         d->slotDetailedTreeView();
2300     });
2301 
2302     QActionGroup *viewGroup = new QActionGroup(this);
2303     shortAction->setActionGroup(viewGroup);
2304     detailedAction->setActionGroup(viewGroup);
2305     treeAction->setActionGroup(viewGroup);
2306     detailedTreeAction->setActionGroup(viewGroup);
2307 
2308     KToggleAction *allowExpansionAction = new KToggleAction(i18n("Allow Expansion in Details View"), this);
2309 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2310     d->m_actionCollection->addAction(QStringLiteral("allow expansion"), allowExpansionAction);
2311 #endif
2312     d->m_actions[AllowExpansionInDetailsView] = allowExpansionAction;
2313     connect(allowExpansionAction, &QAction::toggled, this, [this](bool allow) {
2314         d->slotToggleAllowExpansion(allow);
2315     });
2316 
2317     KToggleAction *showHiddenAction = new KToggleAction(i18n("Show Hidden Files"), this);
2318 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2319     d->m_actionCollection->addAction(QStringLiteral("show hidden"), showHiddenAction);
2320 #endif
2321     d->m_actions[ShowHiddenFiles] = showHiddenAction;
2322     showHiddenAction->setShortcuts(KStandardShortcut::showHideHiddenFiles());
2323     connect(showHiddenAction, &QAction::toggled, this, [this](bool show) {
2324         d->slotToggleHidden(show);
2325     });
2326 
2327     KToggleAction *previewAction = new KToggleAction(i18n("Show Preview Panel"), this);
2328 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2329     d->m_actionCollection->addAction(QStringLiteral("preview"), previewAction);
2330 #endif
2331     d->m_actions[ShowPreviewPanel] = previewAction;
2332     previewAction->setShortcut(Qt::Key_F11);
2333     connect(previewAction, &QAction::toggled, this, [this](bool enable) {
2334         d->togglePreview(enable);
2335     });
2336 
2337     KToggleAction *inlinePreview = new KToggleAction(QIcon::fromTheme(QStringLiteral("view-preview")), i18n("Show Preview"), this);
2338 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2339     d->m_actionCollection->addAction(QStringLiteral("inline preview"), inlinePreview);
2340 #endif
2341     d->m_actions[ShowPreview] = inlinePreview;
2342     inlinePreview->setShortcut(Qt::Key_F12);
2343     connect(inlinePreview, &QAction::toggled, this, [this](bool enable) {
2344         d->toggleInlinePreviews(enable);
2345     });
2346 
2347     QAction *fileManager = new QAction(i18n("Open Containing Folder"), this);
2348 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2349     d->m_actionCollection->addAction(QStringLiteral("file manager"), fileManager);
2350 #endif
2351     d->m_actions[OpenContainingFolder] = fileManager;
2352     fileManager->setIcon(QIcon::fromTheme(QStringLiteral("system-file-manager")));
2353     connect(fileManager, &QAction::triggered, this, [this]() {
2354         d->slotOpenFileManager();
2355     });
2356 
2357     action = new QAction(i18n("Properties"), this);
2358 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2359     d->m_actionCollection->addAction(QStringLiteral("properties"), action);
2360 #endif
2361     d->m_actions[Properties] = action;
2362     action->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")));
2363     action->setShortcut(Qt::ALT | Qt::Key_Return);
2364     connect(action, &QAction::triggered, this, [this]() {
2365         d->slotProperties();
2366     });
2367 
2368     // the view menu actions
2369     KActionMenu *viewMenu = new KActionMenu(i18n("&View Mode"), this);
2370 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2371     d->m_actionCollection->addAction(QStringLiteral("view menu"), viewMenu);
2372 #endif
2373     d->m_actions[ViewModeMenu] = viewMenu;
2374     viewMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
2375     viewMenu->addAction(shortAction);
2376     viewMenu->addAction(detailedAction);
2377     // Comment following lines to hide the extra two modes
2378     viewMenu->addAction(treeAction);
2379     viewMenu->addAction(detailedTreeAction);
2380     // TODO: QAbstractItemView does not offer an action collection. Provide
2381     // an interface to add a custom action collection.
2382 
2383     d->m_itemActions = new KFileItemActions(this);
2384 
2385 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2386     d->m_newFileMenu = new KNewFileMenu(d->m_actionCollection, QStringLiteral("new"), this);
2387 #else
2388     d->m_newFileMenu = new KNewFileMenu(this);
2389 #endif
2390     d->m_actions[KDirOperator::New] = d->m_newFileMenu;
2391     connect(d->m_newFileMenu, &KNewFileMenu::directoryCreated, this, [this](const QUrl &url) {
2392         d->slotDirectoryCreated(url);
2393     });
2394     connect(d->m_newFileMenu, &KNewFileMenu::selectExistingDir, this, [this](const QUrl &url) {
2395         setCurrentItem(url);
2396     });
2397 
2398 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 100)
2399     d->m_actionCollection->addAssociatedWidget(this);
2400     const QList<QAction *> list = d->m_actionCollection->actions();
2401     for (QAction *action : list) {
2402         action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
2403     }
2404 #else
2405     const QList<QAction *> list = d->m_actions.values();
2406     for (QAction *action : list) {
2407         addAction(action);
2408         action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
2409     }
2410 #endif
2411 }
2412 
2413 void KDirOperator::setupMenu()
2414 {
2415     setupMenu(SortActions | ViewActions | FileActions);
2416 }
2417 
2418 void KDirOperator::setupMenu(int whichActions)
2419 {
2420     // first fill the submenus (sort and view)
2421     KActionMenu *sortMenu = static_cast<KActionMenu *>(action(KDirOperator::SortMenu));
2422     sortMenu->menu()->clear();
2423     sortMenu->addAction(action(KDirOperator::SortByName));
2424     sortMenu->addAction(action(KDirOperator::SortBySize));
2425     sortMenu->addAction(action(KDirOperator::SortByDate));
2426     sortMenu->addAction(action(KDirOperator::SortByType));
2427     sortMenu->addSeparator();
2428     sortMenu->addAction(action(KDirOperator::SortAscending));
2429     sortMenu->addAction(action(KDirOperator::SortDescending));
2430     sortMenu->addSeparator();
2431     sortMenu->addAction(action(KDirOperator::SortFoldersFirst));
2432     sortMenu->addAction(action(KDirOperator::SortHiddenFilesLast));
2433 
2434     // now plug everything into the popupmenu
2435     d->m_actionMenu->menu()->clear();
2436     if (whichActions & NavActions) {
2437         d->m_actionMenu->addAction(action(KDirOperator::Up));
2438         d->m_actionMenu->addAction(action(KDirOperator::Back));
2439         d->m_actionMenu->addAction(action(KDirOperator::Forward));
2440         d->m_actionMenu->addAction(action(KDirOperator::Home));
2441         d->m_actionMenu->addSeparator();
2442     }
2443 
2444     if (whichActions & FileActions) {
2445         d->m_actionMenu->addAction(action(KDirOperator::New));
2446 
2447         d->m_actionMenu->addAction(action(KDirOperator::Rename));
2448         action(KDirOperator::Rename)->setEnabled(KProtocolManager::supportsMoving(d->m_currUrl));
2449 
2450         if (d->m_currUrl.isLocalFile() && !(QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
2451             d->m_actionMenu->addAction(action(KDirOperator::Trash));
2452         }
2453         KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("KDE"));
2454         const bool del = !d->m_currUrl.isLocalFile() || (QApplication::keyboardModifiers() & Qt::ShiftModifier) || cg.readEntry("ShowDeleteCommand", false);
2455         if (del) {
2456             d->m_actionMenu->addAction(action(KDirOperator::Delete));
2457         }
2458         d->m_actionMenu->addSeparator();
2459     }
2460 
2461     if (whichActions & SortActions) {
2462         d->m_actionMenu->addAction(sortMenu);
2463         if (!(whichActions & ViewActions)) {
2464             d->m_actionMenu->addSeparator();
2465         }
2466     }
2467 
2468     if (whichActions & ViewActions) {
2469         d->m_actionMenu->addAction(action(KDirOperator::ViewModeMenu));
2470         d->m_actionMenu->addAction(action(KDirOperator::Reload));
2471         d->m_actionMenu->addSeparator();
2472     }
2473 
2474     if (whichActions & FileActions) {
2475         d->m_actionMenu->addAction(action(KDirOperator::OpenContainingFolder));
2476         d->m_actionMenu->addAction(action(KDirOperator::Properties));
2477     }
2478 }
2479 
2480 void KDirOperator::updateSortActions()
2481 {
2482     QAction *ascending = action(KDirOperator::SortAscending);
2483     QAction *descending = action(KDirOperator::SortDescending);
2484 
2485     if (KFile::isSortByName(d->m_sorting)) {
2486         action(KDirOperator::SortByName)->setChecked(true);
2487         descending->setText(i18nc("Sort descending", "Z-A"));
2488         ascending->setText(i18nc("Sort ascending", "A-Z"));
2489     } else if (KFile::isSortByDate(d->m_sorting)) {
2490         action(KDirOperator::SortByDate)->setChecked(true);
2491         descending->setText(i18nc("Sort descending", "Newest First"));
2492         ascending->setText(i18nc("Sort ascending", "Oldest First"));
2493     } else if (KFile::isSortBySize(d->m_sorting)) {
2494         action(KDirOperator::SortBySize)->setChecked(true);
2495         descending->setText(i18nc("Sort descending", "Largest First"));
2496         ascending->setText(i18nc("Sort ascending", "Smallest First"));
2497     } else if (KFile::isSortByType(d->m_sorting)) {
2498         action(KDirOperator::SortByType)->setChecked(true);
2499         descending->setText(i18nc("Sort descending", "Z-A"));
2500         ascending->setText(i18nc("Sort ascending", "A-Z"));
2501     }
2502     ascending->setChecked(!(d->m_sorting & QDir::Reversed));
2503     descending->setChecked(d->m_sorting & QDir::Reversed);
2504     action(KDirOperator::SortFoldersFirst)->setChecked(d->m_sorting & QDir::DirsFirst);
2505 }
2506 
2507 void KDirOperator::updateViewActions()
2508 {
2509     KFile::FileView fv = static_cast<KFile::FileView>(d->m_viewKind);
2510 
2511     // QAction *separateDirs = d->actionCollection->action("separate dirs");
2512     // separateDirs->setChecked(KFile::isSeparateDirs(fv) &&
2513     //                         separateDirs->isEnabled());
2514 
2515     action(KDirOperator::ShortView)->setChecked(KFile::isSimpleView(fv));
2516     action(KDirOperator::DetailedView)->setChecked(KFile::isDetailView(fv));
2517     action(KDirOperator::TreeView)->setChecked(KFile::isTreeView(fv));
2518     action(KDirOperator::DetailedTreeView)->setChecked(KFile::isDetailTreeView(fv));
2519 
2520     // dolphin style views
2521     action(KDirOperator::ViewIconsView)->setChecked(KFile::isSimpleView(fv) && d->m_decorationPosition == QStyleOptionViewItem::Top);
2522     action(KDirOperator::ViewCompactView)->setChecked(KFile::isSimpleView(fv) && d->m_decorationPosition == QStyleOptionViewItem::Left);
2523     action(KDirOperator::ViewDetailsView)->setChecked(KFile::isDetailTreeView(fv) || KFile::isDetailView(fv));
2524 }
2525 
2526 void KDirOperator::readConfig(const KConfigGroup &configGroup)
2527 {
2528     d->m_defaultView = 0;
2529     QString viewStyle = configGroup.readEntry("View Style", "DetailTree");
2530     if (viewStyle == QLatin1String("Detail")) {
2531         d->m_defaultView |= KFile::Detail;
2532     } else if (viewStyle == QLatin1String("Tree")) {
2533         d->m_defaultView |= KFile::Tree;
2534     } else if (viewStyle == QLatin1String("DetailTree")) {
2535         d->m_defaultView |= KFile::DetailTree;
2536     } else {
2537         d->m_defaultView |= KFile::Simple;
2538     }
2539     // if (configGroup.readEntry(QLatin1String("Separate Directories"),
2540     //                          DefaultMixDirsAndFiles)) {
2541     //    d->defaultView |= KFile::SeparateDirs;
2542     //}
2543     if (configGroup.readEntry(QStringLiteral("Show Preview"), false)) {
2544         d->m_defaultView |= KFile::PreviewContents;
2545     }
2546 
2547     d->m_previewWidth = configGroup.readEntry(QStringLiteral("Preview Width"), 100);
2548 
2549     if (configGroup.readEntry(QStringLiteral("Show hidden files"), DefaultShowHidden)) {
2550         action(KDirOperator::ShowHiddenFiles)->setChecked(true);
2551         d->m_dirLister->setShowHiddenFiles(true);
2552     }
2553 
2554     if (configGroup.readEntry(QStringLiteral("Allow Expansion"), DefaultShowHidden)) {
2555         action(KDirOperator::AllowExpansionInDetailsView)->setChecked(true);
2556     }
2557 
2558     const bool hiddenFilesLast = configGroup.readEntry(QStringLiteral("Sort hidden files last"), DefaultHiddenFilesLast);
2559     action(KDirOperator::SortHiddenFilesLast)->setChecked(hiddenFilesLast);
2560 
2561     QDir::SortFlags sorting = QDir::Name;
2562     if (configGroup.readEntry(QStringLiteral("Sort directories first"), DefaultDirsFirst)) {
2563         sorting |= QDir::DirsFirst;
2564     }
2565     QString name = QStringLiteral("Name");
2566     QString sortBy = configGroup.readEntry(QStringLiteral("Sort by"), name);
2567     if (sortBy == name) {
2568         sorting |= QDir::Name;
2569     } else if (sortBy == QLatin1String("Size")) {
2570         sorting |= QDir::Size;
2571     } else if (sortBy == QLatin1String("Date")) {
2572         sorting |= QDir::Time;
2573     } else if (sortBy == QLatin1String("Type")) {
2574         sorting |= QDir::Type;
2575     }
2576     if (configGroup.readEntry(QStringLiteral("Sort reversed"), DefaultSortReversed)) {
2577         sorting |= QDir::Reversed;
2578     }
2579     d->updateSorting(sorting);
2580 
2581     if (d->m_inlinePreviewState == KDirOperatorPrivate::NotForced) {
2582         d->m_showPreviews = configGroup.readEntry(QStringLiteral("Show Inline Previews"), true);
2583     }
2584     QStyleOptionViewItem::Position pos =
2585         (QStyleOptionViewItem::Position)configGroup.readEntry(QStringLiteral("Decoration position"), (int)QStyleOptionViewItem::Top);
2586     setDecorationPosition(pos);
2587 }
2588 
2589 void KDirOperator::writeConfig(KConfigGroup &configGroup)
2590 {
2591     QString sortBy = QStringLiteral("Name");
2592     if (KFile::isSortBySize(d->m_sorting)) {
2593         sortBy = QStringLiteral("Size");
2594     } else if (KFile::isSortByDate(d->m_sorting)) {
2595         sortBy = QStringLiteral("Date");
2596     } else if (KFile::isSortByType(d->m_sorting)) {
2597         sortBy = QStringLiteral("Type");
2598     }
2599 
2600     configGroup.writeEntry(QStringLiteral("Sort by"), sortBy);
2601 
2602     configGroup.writeEntry(QStringLiteral("Sort reversed"), action(KDirOperator::SortDescending)->isChecked());
2603 
2604     configGroup.writeEntry(QStringLiteral("Sort directories first"), action(KDirOperator::SortFoldersFirst)->isChecked());
2605 
2606     const bool hiddenFilesLast = action(KDirOperator::SortHiddenFilesLast)->isChecked();
2607     configGroup.writeEntry(QStringLiteral("Sort hidden files last"), hiddenFilesLast);
2608 
2609     // don't save the preview when an application specific preview is in use.
2610     bool appSpecificPreview = false;
2611     if (d->m_preview) {
2612         KFileMetaPreview *tmp = dynamic_cast<KFileMetaPreview *>(d->m_preview);
2613         appSpecificPreview = (tmp == nullptr);
2614     }
2615 
2616     if (!appSpecificPreview) {
2617         KToggleAction *previewAction = static_cast<KToggleAction *>(action(KDirOperator::ShowPreviewPanel));
2618         if (previewAction->isEnabled()) {
2619             bool hasPreview = previewAction->isChecked();
2620             configGroup.writeEntry(QStringLiteral("Show Preview"), hasPreview);
2621 
2622             if (hasPreview) {
2623                 // remember the width of the preview widget
2624                 QList<int> sizes = d->m_splitter->sizes();
2625                 Q_ASSERT(sizes.count() == 2);
2626                 configGroup.writeEntry(QStringLiteral("Preview Width"), sizes[1]);
2627             }
2628         }
2629     }
2630 
2631     configGroup.writeEntry(QStringLiteral("Show hidden files"), action(KDirOperator::ShowHiddenFiles)->isChecked());
2632 
2633     configGroup.writeEntry(QStringLiteral("Allow Expansion"), action(KDirOperator::AllowExpansionInDetailsView)->isChecked());
2634 
2635     KFile::FileView fv = static_cast<KFile::FileView>(d->m_viewKind);
2636     QString style;
2637     if (KFile::isDetailView(fv)) {
2638         style = QStringLiteral("Detail");
2639     } else if (KFile::isSimpleView(fv)) {
2640         style = QStringLiteral("Simple");
2641     } else if (KFile::isTreeView(fv)) {
2642         style = QStringLiteral("Tree");
2643     } else if (KFile::isDetailTreeView(fv)) {
2644         style = QStringLiteral("DetailTree");
2645     }
2646     configGroup.writeEntry(QStringLiteral("View Style"), style);
2647 
2648     if (d->m_inlinePreviewState == KDirOperatorPrivate::NotForced) {
2649         configGroup.writeEntry(QStringLiteral("Show Inline Previews"), d->m_showPreviews);
2650         d->writeIconZoomSettingsIfNeeded();
2651     }
2652 
2653     configGroup.writeEntry(QStringLiteral("Decoration position"), (int)d->m_decorationPosition);
2654 }
2655 
2656 void KDirOperatorPrivate::writeIconZoomSettingsIfNeeded()
2657 {
2658     // must match behavior of iconSizeForViewType
2659     if (m_configGroup && m_itemView) {
2660         ZoomSettingsForView zoomSettings = zoomSettingsForView();
2661         m_configGroup->writeEntry(zoomSettings.name, m_iconSize);
2662     }
2663 }
2664 
2665 void KDirOperator::resizeEvent(QResizeEvent *)
2666 {
2667     // resize the m_splitter and assure that the width of
2668     // the preview widget is restored
2669     QList<int> sizes = d->m_splitter->sizes();
2670     const bool hasPreview = (sizes.count() == 2);
2671 
2672     d->m_splitter->resize(size());
2673     sizes = d->m_splitter->sizes();
2674 
2675     const bool restorePreviewWidth = hasPreview && (d->m_previewWidth != sizes[1]);
2676     if (restorePreviewWidth) {
2677         const int availableWidth = sizes[0] + sizes[1];
2678         sizes[0] = availableWidth - d->m_previewWidth;
2679         sizes[1] = d->m_previewWidth;
2680         d->m_splitter->setSizes(sizes);
2681     }
2682     if (hasPreview) {
2683         d->m_previewWidth = sizes[1];
2684     }
2685 
2686     if (d->m_progressBar->parent() == this) {
2687         // Might be reparented into a statusbar
2688         const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
2689         d->m_progressBar->move(frameWidth, height() - d->m_progressBar->height() - frameWidth);
2690     }
2691 }
2692 
2693 void KDirOperator::keyPressEvent(QKeyEvent *e) // TODO KF6 remove
2694 {
2695     QWidget::keyPressEvent(e);
2696 }
2697 
2698 void KDirOperator::setOnlyDoubleClickSelectsFiles(bool enable)
2699 {
2700     d->m_onlyDoubleClickSelectsFiles = enable;
2701     // TODO: port to QAbstractItemModel
2702     // if (d->itemView != 0) {
2703     //    d->itemView->setOnlyDoubleClickSelectsFiles(enable);
2704     //}
2705 }
2706 
2707 bool KDirOperator::onlyDoubleClickSelectsFiles() const
2708 {
2709     return d->m_onlyDoubleClickSelectsFiles;
2710 }
2711 
2712 void KDirOperator::setFollowNewDirectories(bool enable)
2713 {
2714     d->m_followNewDirectories = enable;
2715 }
2716 
2717 bool KDirOperator::followNewDirectories() const
2718 {
2719     return d->m_followNewDirectories;
2720 }
2721 
2722 void KDirOperator::setFollowSelectedDirectories(bool enable)
2723 {
2724     d->m_followSelectedDirectories = enable;
2725 }
2726 
2727 bool KDirOperator::followSelectedDirectories() const
2728 {
2729     return d->m_followSelectedDirectories;
2730 }
2731 
2732 void KDirOperatorPrivate::slotStarted()
2733 {
2734     m_progressBar->setValue(0);
2735     // delay showing the progressbar for one second
2736     m_progressDelayTimer->setSingleShot(true);
2737     m_progressDelayTimer->start(1000);
2738 }
2739 
2740 void KDirOperatorPrivate::slotShowProgress()
2741 {
2742     m_progressBar->raise();
2743     m_progressBar->show();
2744 }
2745 
2746 void KDirOperatorPrivate::slotProgress(int percent)
2747 {
2748     m_progressBar->setValue(percent);
2749 }
2750 
2751 void KDirOperatorPrivate::slotIOFinished()
2752 {
2753     m_progressDelayTimer->stop();
2754     slotProgress(100);
2755     m_progressBar->hide();
2756     Q_EMIT q->finishedLoading();
2757     q->resetCursor();
2758 
2759     if (m_preview) {
2760         m_preview->clearPreview();
2761     }
2762 
2763     // m_lastUrl can be empty when e.g. kfilewidget is first opened
2764     if (!m_lastUrl.isEmpty() && m_dirHighlighting) {
2765         q->setCurrentItem(m_lastUrl);
2766     }
2767 }
2768 
2769 void KDirOperatorPrivate::slotCanceled()
2770 {
2771     Q_EMIT q->finishedLoading();
2772     q->resetCursor();
2773 }
2774 
2775 QProgressBar *KDirOperator::progressBar() const
2776 {
2777     return d->m_progressBar;
2778 }
2779 
2780 void KDirOperator::clearHistory()
2781 {
2782     qDeleteAll(d->m_backStack);
2783     d->m_backStack.clear();
2784     action(KDirOperator::Back)->setEnabled(false);
2785 
2786     qDeleteAll(d->m_forwardStack);
2787     d->m_forwardStack.clear();
2788     action(KDirOperator::Forward)->setEnabled(false);
2789 }
2790 
2791 void KDirOperator::setEnableDirHighlighting(bool enable)
2792 {
2793     d->m_dirHighlighting = enable;
2794 }
2795 
2796 bool KDirOperator::dirHighlighting() const
2797 {
2798     return d->m_dirHighlighting;
2799 }
2800 
2801 bool KDirOperator::dirOnlyMode() const
2802 {
2803     return dirOnlyMode(d->m_mode);
2804 }
2805 
2806 bool KDirOperator::dirOnlyMode(uint mode)
2807 {
2808     return ((mode & KFile::Directory) && (mode & (KFile::File | KFile::Files)) == 0);
2809 }
2810 
2811 void KDirOperatorPrivate::slotProperties()
2812 {
2813     if (m_itemView == nullptr) {
2814         return;
2815     }
2816 
2817     const KFileItemList list = q->selectedItems();
2818     if (!list.isEmpty()) {
2819         auto *dialog = new KPropertiesDialog(list, q);
2820         dialog->setAttribute(Qt::WA_DeleteOnClose);
2821         dialog->setModal(true);
2822         dialog->show();
2823     }
2824 }
2825 
2826 void KDirOperatorPrivate::slotActivated(const QModelIndex &index)
2827 {
2828     const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
2829     KFileItem item = m_dirModel->itemForIndex(dirIndex);
2830 
2831     const Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
2832     if (item.isNull() || (modifiers & Qt::ShiftModifier) || (modifiers & Qt::ControlModifier)) {
2833         return;
2834     }
2835 
2836     if (item.isDir()) {
2837         // Only allow disabling following selected directories on Tree and
2838         // DetailTree views as selected directories in these views still expand
2839         // when selected. For other views, disabling following selected
2840         // directories would make selecting a directory a noop which is
2841         // unintuitive.
2842         if (m_followSelectedDirectories || (m_viewKind != KFile::Tree && m_viewKind != KFile::DetailTree)) {
2843             q->selectDir(item);
2844         }
2845     } else {
2846         q->selectFile(item);
2847     }
2848 }
2849 
2850 void KDirOperatorPrivate::slotSelectionChanged()
2851 {
2852     if (m_itemView == nullptr) {
2853         return;
2854     }
2855 
2856     // In the multiselection mode each selection change is indicated by
2857     // emitting a null item. Also when the selection has been cleared, a
2858     // null item must be emitted.
2859     const bool multiSelectionMode = (m_itemView->selectionMode() == QAbstractItemView::ExtendedSelection);
2860     const bool hasSelection = m_itemView->selectionModel()->hasSelection();
2861     if (multiSelectionMode || !hasSelection) {
2862         KFileItem nullItem;
2863         q->highlightFile(nullItem);
2864     } else {
2865         const KFileItem selectedItem = q->selectedItems().constFirst();
2866         q->highlightFile(selectedItem);
2867     }
2868 }
2869 
2870 void KDirOperatorPrivate::openContextMenu(const QPoint &pos)
2871 {
2872     const QModelIndex proxyIndex = m_itemView->indexAt(pos);
2873     const QModelIndex dirIndex = m_proxyModel->mapToSource(proxyIndex);
2874     KFileItem item = m_dirModel->itemForIndex(dirIndex);
2875 
2876     if (item.isNull()) {
2877         return;
2878     }
2879 
2880     q->activatedMenu(item, QCursor::pos());
2881 }
2882 
2883 void KDirOperatorPrivate::triggerPreview(const QModelIndex &index)
2884 {
2885     if ((m_preview != nullptr && !m_preview->isHidden()) && index.isValid() && (index.column() == KDirModel::Name)) {
2886         const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
2887         const KFileItem item = m_dirModel->itemForIndex(dirIndex);
2888 
2889         if (item.isNull()) {
2890             return;
2891         }
2892 
2893         if (!item.isDir()) {
2894             m_previewUrl = item.url();
2895             showPreview();
2896         } else {
2897             m_preview->clearPreview();
2898         }
2899     }
2900 }
2901 
2902 void KDirOperatorPrivate::showPreview()
2903 {
2904     if (m_preview != nullptr) {
2905         m_preview->showPreview(m_previewUrl);
2906     }
2907 }
2908 
2909 void KDirOperatorPrivate::slotSplitterMoved(int, int)
2910 {
2911     const QList<int> sizes = m_splitter->sizes();
2912     if (sizes.count() == 2) {
2913         // remember the width of the preview widget (see KDirOperator::resizeEvent())
2914         m_previewWidth = sizes[1];
2915     }
2916 }
2917 
2918 void KDirOperatorPrivate::assureVisibleSelection()
2919 {
2920     if (m_itemView == nullptr) {
2921         return;
2922     }
2923 
2924     QItemSelectionModel *selModel = m_itemView->selectionModel();
2925     if (selModel->hasSelection()) {
2926         const QModelIndex index = selModel->currentIndex();
2927         m_itemView->scrollTo(index, QAbstractItemView::EnsureVisible);
2928         triggerPreview(index);
2929     }
2930 }
2931 
2932 void KDirOperatorPrivate::synchronizeSortingState(int logicalIndex, Qt::SortOrder order)
2933 {
2934     QDir::SortFlags newSort = m_sorting & ~(QDirSortMask | QDir::Reversed);
2935 
2936     switch (logicalIndex) {
2937     case KDirModel::Name:
2938         newSort |= QDir::Name;
2939         break;
2940     case KDirModel::Size:
2941         newSort |= QDir::Size;
2942         break;
2943     case KDirModel::ModifiedTime:
2944         newSort |= QDir::Time;
2945         break;
2946     case KDirModel::Type:
2947         newSort |= QDir::Type;
2948         break;
2949     default:
2950         Q_ASSERT(false);
2951     }
2952 
2953     if (order == Qt::DescendingOrder) {
2954         newSort |= QDir::Reversed;
2955     }
2956 
2957     updateSorting(newSort);
2958 
2959     QMetaObject::invokeMethod(
2960         q,
2961         [this]() {
2962             assureVisibleSelection();
2963         },
2964         Qt::QueuedConnection);
2965 }
2966 
2967 void KDirOperatorPrivate::slotChangeDecorationPosition()
2968 {
2969     if (!m_itemView) {
2970         return;
2971     }
2972 
2973     KDirOperatorIconView *view = qobject_cast<KDirOperatorIconView *>(m_itemView);
2974 
2975     if (!view) {
2976         return;
2977     }
2978 
2979     const bool leftChecked = q->action(KDirOperator::DecorationAtLeft)->isChecked();
2980 
2981     if (leftChecked) {
2982         view->setDecorationPosition(QStyleOptionViewItem::Left);
2983     } else {
2984         view->setDecorationPosition(QStyleOptionViewItem::Top);
2985     }
2986 
2987     m_itemView->update();
2988 }
2989 
2990 void KDirOperatorPrivate::slotExpandToUrl(const QModelIndex &index)
2991 {
2992     QTreeView *treeView = qobject_cast<QTreeView *>(m_itemView);
2993 
2994     if (!treeView) {
2995         return;
2996     }
2997 
2998     const KFileItem item = m_dirModel->itemForIndex(index);
2999 
3000     if (item.isNull()) {
3001         return;
3002     }
3003 
3004     if (!item.isDir()) {
3005         const QModelIndex proxyIndex = m_proxyModel->mapFromSource(index);
3006 
3007         QList<QUrl>::Iterator it = m_itemsToBeSetAsCurrent.begin();
3008         while (it != m_itemsToBeSetAsCurrent.end()) {
3009             const QUrl url = *it;
3010             if (url.matches(item.url(), QUrl::StripTrailingSlash) || url.isParentOf(item.url())) {
3011                 const KFileItem _item = m_dirLister->findByUrl(url);
3012                 if (!_item.isNull() && _item.isDir()) {
3013                     const QModelIndex _index = m_dirModel->indexForItem(_item);
3014                     const QModelIndex _proxyIndex = m_proxyModel->mapFromSource(_index);
3015                     treeView->expand(_proxyIndex);
3016 
3017                     // if we have expanded the last parent of this item, select it
3018                     if (item.url().adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash) == url.adjusted(QUrl::StripTrailingSlash)) {
3019                         treeView->selectionModel()->select(proxyIndex, QItemSelectionModel::Select);
3020                     }
3021                 }
3022                 it = m_itemsToBeSetAsCurrent.erase(it);
3023             } else {
3024                 ++it;
3025             }
3026         }
3027     } else if (!m_itemsToBeSetAsCurrent.contains(item.url())) {
3028         m_itemsToBeSetAsCurrent << item.url();
3029     }
3030 }
3031 
3032 void KDirOperatorPrivate::slotItemsChanged()
3033 {
3034     m_completeListDirty = true;
3035 }
3036 
3037 int KDirOperatorPrivate::iconSizeForViewType(QAbstractItemView *itemView) const
3038 {
3039     // must match behavior of writeIconZoomSettingsIfNeeded
3040     if (!itemView || !m_configGroup) {
3041         return 0;
3042     }
3043 
3044     ZoomSettingsForView zoomSettings = zoomSettingsForView();
3045     return m_configGroup->readEntry(zoomSettings.name, zoomSettings.defaultValue);
3046 }
3047 
3048 KDirOperatorPrivate::ZoomSettingsForView KDirOperatorPrivate::zoomSettingsForView() const
3049 {
3050     KFile::FileView fv = static_cast<KFile::FileView>(m_viewKind);
3051 
3052     KSharedConfigPtr config = KSharedConfig::openConfig();
3053     if (KFile::isSimpleView(fv)) {
3054         KConfigGroup cg(config, "DesktopIcons");
3055         const int desktopIconSize = cg.readEntry("Size", static_cast<int>(KIconLoader::SizeHuge));
3056         if (m_decorationPosition == QStyleOptionViewItem::Top) {
3057             // Simple view decoration above, aka Icons View
3058             return {QStringLiteral("iconViewIconSize"), desktopIconSize};
3059         } else {
3060             // Simple view decoration left, aka compact view
3061             return {QStringLiteral("listViewIconSize"), desktopIconSize};
3062         }
3063     }
3064 
3065     KConfigGroup cg(config, "SmallIcons");
3066     const int smallIconSize = cg.readEntry("Size", static_cast<int>(KIconLoader::SizeSmall));
3067     if (KFile::isTreeView(fv)) {
3068         return {QStringLiteral("treeViewIconSize"), smallIconSize};
3069     } else {
3070         // DetailView and DetailTreeView
3071         return {QStringLiteral("detailViewIconSize"), smallIconSize};
3072     }
3073 }
3074 
3075 void KDirOperator::setViewConfig(KConfigGroup &configGroup)
3076 {
3077     delete d->m_configGroup;
3078     d->m_configGroup = new KConfigGroup(configGroup);
3079 }
3080 
3081 KConfigGroup *KDirOperator::viewConfigGroup() const
3082 {
3083     return d->m_configGroup;
3084 }
3085 
3086 void KDirOperator::setShowHiddenFiles(bool s)
3087 {
3088     action(KDirOperator::ShowHiddenFiles)->setChecked(s);
3089 }
3090 
3091 bool KDirOperator::showHiddenFiles() const
3092 {
3093     return action(KDirOperator::ShowHiddenFiles)->isChecked();
3094 }
3095 
3096 QStyleOptionViewItem::Position KDirOperator::decorationPosition() const
3097 {
3098     return d->m_decorationPosition;
3099 }
3100 
3101 void KDirOperator::setDecorationPosition(QStyleOptionViewItem::Position position)
3102 {
3103     d->m_decorationPosition = position;
3104     const bool decorationAtLeft = d->m_decorationPosition == QStyleOptionViewItem::Left;
3105     action(KDirOperator::DecorationAtLeft)->setChecked(decorationAtLeft);
3106     action(KDirOperator::DecorationAtTop)->setChecked(!decorationAtLeft);
3107 }
3108 
3109 bool KDirOperatorPrivate::isReadable(const QUrl &url)
3110 {
3111     if (!url.isLocalFile()) {
3112         return true; // what else can we say?
3113     }
3114     const QFileInfo fileInfo(url.toLocalFile());
3115 #ifdef Q_OS_WIN
3116     return fileInfo.isReadable() && fileInfo.isDir();
3117 #else
3118     return fileInfo.isReadable();
3119 #endif
3120 }
3121 
3122 void KDirOperatorPrivate::slotDirectoryCreated(const QUrl &url)
3123 {
3124     if (m_followNewDirectories) {
3125         q->setUrl(url, true);
3126     }
3127 }
3128 
3129 void KDirOperator::setSupportedSchemes(const QStringList &schemes)
3130 {
3131     d->m_supportedSchemes = schemes;
3132     rereadDir();
3133 }
3134 
3135 QStringList KDirOperator::supportedSchemes() const
3136 {
3137     return d->m_supportedSchemes;
3138 }
3139 
3140 #include "moc_kdiroperator.cpp"