KIO

kdiroperator.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999, 2000 Stephan Kulow <coolo@kde.org>
4 SPDX-FileCopyrightText: 1999, 2000, 2001, 2002, 2003 Carsten Pfeiffer <pfeiffer@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include <config-kiofilewidgets.h>
10#include <defaults-kfile.h> // ConfigGroup, DefaultShowHidden, DefaultDirsFirst, DefaultSortReversed
11
12#include "../utils_p.h"
13
14#include "kdirmodel.h"
15#include "kdiroperator.h"
16#include "kdiroperatordetailview_p.h"
17#include "kdiroperatoriconview_p.h"
18#include "kdirsortfilterproxymodel.h"
19#include "kfileitem.h"
20#include "kfileitemselectionemblem.h"
21#include "kfilemetapreview_p.h"
22#include "knewfilemenu.h"
23#include "kpreviewwidgetbase.h"
24#include "statjob.h"
25#include <KCompletion>
26#include <KConfigGroup>
27#include <KDirLister>
28#include <KFileItemActions>
29#include <KFileItemListProperties>
30#include <KIO/OpenFileManagerWindowJob>
31#include <KIO/RenameFileDialog>
32#include <KIconLoader>
33#include <KJobWidgets>
34#include <KLocalizedString>
35#include <KMessageBox>
36#include <KProtocolManager>
37#include <KSharedConfig>
38#include <KStandardActions>
39#include <KToggleAction>
40#include <KUrlMimeData>
41#include <kfileitemdelegate.h>
42#include <kfilepreviewgenerator.h>
43#include <kio/copyjob.h>
44#include <kio/deletejob.h>
45#include <kio/deleteortrashjob.h>
46#include <kio/jobuidelegate.h>
47#include <kio/previewjob.h>
48#include <kpropertiesdialog.h>
49
50#include <QActionGroup>
51#include <QApplication>
52#include <QDebug>
53#include <QHeaderView>
54#include <QListView>
55#include <QMenu>
56#include <QMimeDatabase>
57#include <QProgressBar>
58#include <QRegularExpression>
59#include <QScrollBar>
60#include <QScroller>
61#include <QSplitter>
62#include <QStack>
63#include <QTimer>
64#include <QWheelEvent>
65
66#include <memory>
67
68template class QHash<QString, KFileItem>;
69
70// QDir::SortByMask is not only undocumented, it also omits QDir::Type which is another
71// sorting mode.
72static const int QDirSortMask = QDir::SortByMask | QDir::Type;
73
74class KDirOperatorPrivate
75{
76public:
77 explicit KDirOperatorPrivate(KDirOperator *qq)
78 : q(qq)
79 {
80 m_iconSize = static_cast<int>(KIconLoader::SizeSmall);
81 }
82
83 ~KDirOperatorPrivate();
84
85 enum InlinePreviewState {
86 ForcedToFalse = 0,
87 ForcedToTrue,
88 NotForced,
89 };
90
91 // private methods
92 bool checkPreviewInternal() const;
93 bool openUrl(const QUrl &url, KDirLister::OpenUrlFlags flags = KDirLister::NoFlags);
94 int sortColumn() const;
95 Qt::SortOrder sortOrder() const;
96 void updateSorting(QDir::SortFlags sort);
97
98 bool isReadable(const QUrl &url);
99 bool isSchemeSupported(const QString &scheme) const;
100
101 QPoint progressBarPos() const;
102
103 KFile::FileView allViews();
104
105 QMetaObject::Connection m_connection;
106
107 // A pair to store zoom settings for view kinds
108 struct ZoomSettingsForView {
110 int defaultValue;
111 };
112
113 // private slots
114 void slotDetailedView();
115 void slotSimpleView();
116 void slotTreeView();
117 void slotDetailedTreeView();
118 void slotIconsView();
119 void slotCompactView();
120 void slotDetailsView();
121 void slotToggleHidden(bool);
122 void slotToggleAllowExpansion(bool);
123 void togglePreview(bool);
124 void toggleInlinePreviews(bool);
125 void slotOpenFileManager();
126 void slotSortByName();
127 void slotSortBySize();
128 void slotSortByDate();
129 void slotSortByType();
130 void slotSortReversed(bool doReverse);
131 void slotToggleDirsFirst();
132 void slotToggleIconsView();
133 void slotToggleCompactView();
134 void slotToggleDetailsView();
135 void slotToggleIgnoreCase();
136 void slotStarted();
137 void slotProgress(int);
138 void slotShowProgress();
139 void slotIOFinished();
140 void slotCanceled();
141 void slotRedirected(const QUrl &);
142 void slotProperties();
143 void slotActivated(const QModelIndex &);
144 void slotSelectionChanged();
145 void openContextMenu(const QPoint &);
146 void triggerPreview(const QModelIndex &);
147 void showPreview();
148 void slotSplitterMoved(int, int);
149 void assureVisibleSelection();
150 void synchronizeSortingState(int, Qt::SortOrder);
151 void slotChangeDecorationPosition();
152 void slotExpandToUrl(const QModelIndex &);
153 void slotItemsChanged();
154 void slotDirectoryCreated(const QUrl &);
155 void slotAskUserDeleteResult(bool allowDelete, const QList<QUrl> &urls, KIO::AskUserActionInterface::DeletionType deletionType, QWidget *parent);
156
157 int iconSizeForViewType(QAbstractItemView *itemView) const;
158 void writeIconZoomSettingsIfNeeded();
159 ZoomSettingsForView zoomSettingsForView() const;
160
161 QList<QAction *> insertOpenWithActions();
162
163 // private members
164 KDirOperator *const q;
165 QStack<QUrl *> m_backStack; ///< Contains all URLs you can reach with the back button.
166 QStack<QUrl *> m_forwardStack; ///< Contains all URLs you can reach with the forward button.
167
168 QModelIndex m_lastHoveredIndex;
169
170 KDirLister *m_dirLister = nullptr;
171 QUrl m_currUrl;
172
173 KCompletion m_completion;
174 KCompletion m_dirCompletion;
175 QDir::SortFlags m_sorting;
177
178 QSplitter *m_splitter = nullptr;
179
180 QAbstractItemView *m_itemView = nullptr;
181 KDirModel *m_dirModel = nullptr;
182 KDirSortFilterProxyModel *m_proxyModel = nullptr;
183
184 KFileItemList m_pendingMimeTypes;
185
186 // the enum KFile::FileView as an int
187 int m_viewKind;
188 int m_defaultView;
189
190 KFile::Modes m_mode;
191 QProgressBar *m_progressBar = nullptr;
192
193 KPreviewWidgetBase *m_preview = nullptr;
194 QUrl m_previewUrl;
195 int m_previewWidth = 0;
196
197 bool m_completeListDirty = false;
198 bool m_followNewDirectories = true;
199 bool m_followSelectedDirectories = true;
200 bool m_onlyDoubleClickSelectsFiles = !qApp->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick);
201
202 QUrl m_lastUrl; // used for highlighting a directory on back/cdUp
203
204 QTimer *m_progressDelayTimer = nullptr;
205 KActionMenu *m_actionMenu = nullptr;
206 KActionCollection *m_actionCollection = nullptr;
207 KNewFileMenu *m_newFileMenu = nullptr;
208 KConfigGroup *m_configGroup = nullptr;
209 KFilePreviewGenerator *m_previewGenerator = nullptr;
210 KActionMenu *m_decorationMenu = nullptr;
211 KToggleAction *m_leftAction = nullptr;
212 KFileItemActions *m_itemActions = nullptr;
213
214 int m_dropOptions = 0;
215 int m_iconSize = 0;
216 InlinePreviewState m_inlinePreviewState = NotForced;
217 bool m_dirHighlighting = true;
218 bool m_showPreviews = false;
219 bool m_shouldFetchForItems = false;
220 bool m_isSaving = false;
221 bool m_showOpenWithActions = false;
222 bool m_isTouchEvent = false;
223 bool m_isTouchDrag = false;
224 bool m_keyNavigation = false;
225
226 QList<QUrl> m_itemsToBeSetAsCurrent;
227 QStringList m_supportedSchemes;
228
230};
231
232KDirOperatorPrivate::~KDirOperatorPrivate()
233{
234 if (m_itemView) {
235 // fix libc++ crash: its unique_ptr implementation has already set 'd' to null
236 // and the event filter will get a QEvent::Leave event if we don't remove it.
237 m_itemView->removeEventFilter(q);
238 m_itemView->viewport()->removeEventFilter(q);
239 }
240
241 delete m_itemView;
242 m_itemView = nullptr;
243
244 // TODO:
245 // if (configGroup) {
246 // itemView->writeConfig(configGroup);
247 // }
248
249 qDeleteAll(m_backStack);
250 qDeleteAll(m_forwardStack);
251
252 // The parent KDirOperator will delete these
253 m_preview = nullptr;
254 m_proxyModel = nullptr;
255 m_dirModel = nullptr;
256 m_progressDelayTimer = nullptr;
257
258 m_dirLister = nullptr; // deleted by KDirModel
259
260 delete m_configGroup;
261 m_configGroup = nullptr;
262}
263
264QPoint KDirOperatorPrivate::progressBarPos() const
265{
266 const int frameWidth = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
267 return QPoint(frameWidth, q->height() - m_progressBar->height() - frameWidth);
268}
269
271 : QWidget(parent)
272 , d(new KDirOperatorPrivate(this))
273{
274 d->m_splitter = new QSplitter(this);
275 d->m_splitter->setChildrenCollapsible(false);
276 connect(d->m_splitter, &QSplitter::splitterMoved, this, [this](int pos, int index) {
277 d->slotSplitterMoved(pos, index);
278 });
279
280 d->m_preview = nullptr;
281
282 d->m_mode = KFile::File;
283 d->m_viewKind = KFile::Simple;
284
285 if (_url.isEmpty()) { // no dir specified -> current dir
286 QString strPath = QDir::currentPath();
287 strPath.append(QLatin1Char('/'));
288 d->m_currUrl = QUrl::fromLocalFile(strPath);
289 } else {
290 d->m_currUrl = _url;
291 if (d->m_currUrl.scheme().isEmpty()) {
292 d->m_currUrl.setScheme(QStringLiteral("file"));
293 }
294
295 // make sure we have a trailing slash!
296 Utils::appendSlashToPath(d->m_currUrl);
297 }
298
299 // We set the direction of this widget to LTR, since even on RTL desktops
300 // viewing directory listings in RTL mode makes people's head explode.
301 // Is this the correct place? Maybe it should be in some lower level widgets...?
304
306
307 d->m_progressBar = new QProgressBar(this);
308 d->m_progressBar->setObjectName(QStringLiteral("d->m_progressBar"));
309 d->m_progressBar->setFormat(i18nc("Loading bar percent value", "%p%"));
310 d->m_progressBar->adjustSize();
311 const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
312 d->m_progressBar->move(frameWidth, height() - d->m_progressBar->height() - frameWidth);
313
314 d->m_progressDelayTimer = new QTimer(this);
315 d->m_progressDelayTimer->setObjectName(QStringLiteral("d->m_progressBar delay timer"));
316 connect(d->m_progressDelayTimer, &QTimer::timeout, this, [this]() {
317 d->slotShowProgress();
318 });
319
320 d->m_completeListDirty = false;
321
322 // action stuff
323 setupActions();
324 setupMenu();
325
326 d->m_sorting = QDir::NoSort; // so updateSorting() doesn't think nothing has changed
327 d->updateSorting(QDir::Name | QDir::DirsFirst);
328
330 setAcceptDrops(true);
331}
332
334{
335 resetCursor();
336 disconnect(d->m_dirLister, nullptr, this, nullptr);
337}
338
340{
341 d->updateSorting(spec);
342}
343
345{
346 return d->m_sorting;
347}
348
350{
351#ifdef Q_OS_WIN
352 if (url().isLocalFile()) {
353 const QString path = url().toLocalFile();
354 if (path.length() == 3) {
355 return (path[0].isLetter() && path[1] == QLatin1Char(':') && path[2] == QLatin1Char('/'));
356 }
357 return false;
358 } else
359#endif
360 return url().path() == QLatin1String("/");
361}
362
364{
365 return d->m_dirLister;
366}
367
369{
370 if (qApp) {
372 }
373 d->m_progressBar->hide();
374}
375
377{
378 d->updateSorting((d->m_sorting & ~QDirSortMask) | QDir::Name);
379}
380
382{
383 d->updateSorting((d->m_sorting & ~QDirSortMask) | QDir::Size);
384}
385
387{
388 d->updateSorting((d->m_sorting & ~QDirSortMask) | QDir::Time);
389}
390
392{
393 d->updateSorting((d->m_sorting & ~QDirSortMask) | QDir::Type);
394}
395
397{
398 // toggle it, hence the inversion of current state
399 d->slotSortReversed(!(d->m_sorting & QDir::Reversed));
400}
401
403{
404 d->slotToggleDirsFirst();
405}
406
408{
409 if (d->m_proxyModel != nullptr) {
410 Qt::CaseSensitivity cs = d->m_proxyModel->sortCaseSensitivity();
412 d->m_proxyModel->setSortCaseSensitivity(cs);
413 }
414}
415
417{
418 const bool hasSelection = (d->m_itemView != nullptr) && d->m_itemView->selectionModel()->hasSelection();
419 action(KDirOperator::Rename)->setEnabled(hasSelection);
420 action(KDirOperator::Trash)->setEnabled(hasSelection);
421 action(KDirOperator::Delete)->setEnabled(hasSelection);
423}
424
426{
427 const bool showPreview = (w != nullptr);
428 if (showPreview) {
429 d->m_viewKind = (d->m_viewKind | KFile::PreviewContents);
430 } else {
431 d->m_viewKind = (d->m_viewKind & ~KFile::PreviewContents);
432 }
433
434 delete d->m_preview;
435 d->m_preview = w;
436
437 if (w) {
438 d->m_splitter->addWidget(w);
439 }
440
441 KToggleAction *previewAction = static_cast<KToggleAction *>(action(ShowPreviewPanel));
442 previewAction->setEnabled(showPreview);
443 previewAction->setChecked(showPreview);
444 setViewMode(static_cast<KFile::FileView>(d->m_viewKind));
445}
446
448{
449 KFileItemList itemList;
450 if (d->m_itemView == nullptr) {
451 return itemList;
452 }
453
454 const QItemSelection selection = d->m_proxyModel->mapSelectionToSource(d->m_itemView->selectionModel()->selection());
455
456 const QModelIndexList indexList = selection.indexes();
457 for (const QModelIndex &index : indexList) {
458 KFileItem item = d->m_dirModel->itemForIndex(index);
459 if (!item.isNull()) {
460 itemList.append(item);
461 }
462 }
463
464 return itemList;
465}
466
467bool KDirOperator::isSelected(const KFileItem &item) const
468{
469 if ((item.isNull()) || (d->m_itemView == nullptr)) {
470 return false;
471 }
472
473 const QModelIndex dirIndex = d->m_dirModel->indexForItem(item);
474 const QModelIndex proxyIndex = d->m_proxyModel->mapFromSource(dirIndex);
475 return d->m_itemView->selectionModel()->isSelected(proxyIndex);
476}
477
479{
480 return (d->m_dirLister == nullptr) ? 0 : d->m_dirLister->directories().count();
481}
482
484{
485 return (d->m_dirLister == nullptr) ? 0 : d->m_dirLister->items().count() - numDirs();
486}
487
489{
490 return const_cast<KCompletion *>(&d->m_completion);
491}
492
494{
495 return const_cast<KCompletion *>(&d->m_dirCompletion);
496}
497
499{
500 return d->m_actions[action];
501}
502
504{
505 return d->m_actions.values();
506}
507
508KFile::FileView KDirOperatorPrivate::allViews()
509{
510 return static_cast<KFile::FileView>(KFile::Simple | KFile::Detail | KFile::Tree | KFile::DetailTree);
511}
512
513void KDirOperatorPrivate::slotDetailedView()
514{
515 // save old zoom settings
516 writeIconZoomSettingsIfNeeded();
517
518 KFile::FileView view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Detail);
519 q->setViewMode(view);
520}
521
522void KDirOperatorPrivate::slotSimpleView()
523{
524 // save old zoom settings
525 writeIconZoomSettingsIfNeeded();
526
527 KFile::FileView view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Simple);
528 q->setViewMode(view);
529}
530
531void KDirOperatorPrivate::slotTreeView()
532{
533 // save old zoom settings
534 writeIconZoomSettingsIfNeeded();
535
536 KFile::FileView view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Tree);
537 q->setViewMode(view);
538}
539
540void KDirOperatorPrivate::slotDetailedTreeView()
541{
542 // save old zoom settings
543 writeIconZoomSettingsIfNeeded();
544
545 KFile::FileView view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::DetailTree);
546 q->setViewMode(view);
547}
548
549void KDirOperatorPrivate::slotToggleAllowExpansion(bool allow)
550{
551 KFile::FileView view = KFile::Detail;
552 if (allow) {
553 view = KFile::DetailTree;
554 }
555 q->setViewMode(view);
556}
557
558void KDirOperatorPrivate::slotToggleHidden(bool show)
559{
560 m_dirLister->setShowHiddenFiles(show);
561 q->updateDir();
562 assureVisibleSelection();
563}
564
565void KDirOperatorPrivate::togglePreview(bool on)
566{
567 if (on) {
568 m_viewKind |= KFile::PreviewContents;
569 if (m_preview == nullptr) {
570 m_preview = new KFileMetaPreview(q);
571 q->action(KDirOperator::ShowPreviewPanel)->setChecked(true);
572 m_splitter->addWidget(m_preview);
573 }
574
575 m_preview->show();
576
577 auto assureVisFunc = [this]() {
578 assureVisibleSelection();
579 };
581 if (m_itemView != nullptr) {
582 const QModelIndex index = m_itemView->selectionModel()->currentIndex();
583 if (index.isValid()) {
584 triggerPreview(index);
585 }
586 }
587 } else if (m_preview != nullptr) {
588 m_viewKind = m_viewKind & ~KFile::PreviewContents;
589 m_preview->hide();
590 }
591}
592
593void KDirOperatorPrivate::toggleInlinePreviews(bool show)
594{
595 if (m_showPreviews == show) {
596 return;
597 }
598
599 m_showPreviews = show;
600
601 if (!m_previewGenerator) {
602 return;
603 }
604
605 m_previewGenerator->setPreviewShown(show);
606}
607
608void KDirOperatorPrivate::slotOpenFileManager()
609{
610 const KFileItemList list = q->selectedItems();
611 if (list.isEmpty()) {
613 } else {
615 }
616}
617
618void KDirOperatorPrivate::slotSortByName()
619{
620 q->sortByName();
621}
622
623void KDirOperatorPrivate::slotSortBySize()
624{
625 q->sortBySize();
626}
627
628void KDirOperatorPrivate::slotSortByDate()
629{
630 q->sortByDate();
631}
632
633void KDirOperatorPrivate::slotSortByType()
634{
635 q->sortByType();
636}
637
638void KDirOperatorPrivate::slotSortReversed(bool doReverse)
639{
640 QDir::SortFlags s = m_sorting & ~QDir::Reversed;
641 if (doReverse) {
642 s |= QDir::Reversed;
643 }
644 updateSorting(s);
645}
646
647void KDirOperatorPrivate::slotToggleDirsFirst()
648{
649 QDir::SortFlags s = (m_sorting ^ QDir::DirsFirst);
650 updateSorting(s);
651}
652
653void KDirOperatorPrivate::slotIconsView()
654{
655 // save old zoom settings
656 writeIconZoomSettingsIfNeeded();
657
658 // Put the icons on top
659 q->action(KDirOperator::DecorationAtTop)->setChecked(true);
660 m_decorationPosition = QStyleOptionViewItem::Top;
661
662 // Switch to simple view
663 KFile::FileView fileView = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Simple);
664 q->setViewMode(fileView);
665}
666
667void KDirOperatorPrivate::slotCompactView()
668{
669 // save old zoom settings
670 writeIconZoomSettingsIfNeeded();
671
672 // Put the icons on the side
673 q->action(KDirOperator::DecorationAtLeft)->setChecked(true);
674 m_decorationPosition = QStyleOptionViewItem::Left;
675
676 // Switch to simple view
677 KFile::FileView fileView = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Simple);
678 q->setViewMode(fileView);
679}
680
681void KDirOperatorPrivate::slotDetailsView()
682{
683 // save old zoom settings
684 writeIconZoomSettingsIfNeeded();
685
686 KFile::FileView view;
687 if (q->action(KDirOperator::AllowExpansionInDetailsView)->isChecked()) {
688 view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::DetailTree);
689 } else {
690 view = static_cast<KFile::FileView>((m_viewKind & ~allViews()) | KFile::Detail);
691 }
692 q->setViewMode(view);
693}
694
695void KDirOperatorPrivate::slotToggleIgnoreCase()
696{
697 // TODO: port to Qt4's QAbstractItemView
698 /*if ( !d->fileView )
699 return;
700
701 QDir::SortFlags sorting = d->fileView->sorting();
702 if ( !KFile::isSortCaseInsensitive( sorting ) )
703 d->fileView->setSorting( sorting | QDir::IgnoreCase );
704 else
705 d->fileView->setSorting( sorting & ~QDir::IgnoreCase );
706 d->sorting = d->fileView->sorting();*/
707}
708
710{
711 d->m_newFileMenu->setWorkingDirectory(url());
712 d->m_newFileMenu->createDirectory();
713}
714
715KIO::DeleteJob *KDirOperator::del(const KFileItemList &items, QWidget *parent, bool ask, bool showProgress)
716{
717 if (items.isEmpty()) {
718 KMessageBox::information(parent, i18n("You did not select a file to delete."), i18n("Nothing to Delete"));
719 return nullptr;
720 }
721
722 if (parent == nullptr) {
723 parent = this;
724 }
725
726 const QList<QUrl> urls = items.urlList();
727
728 bool doIt = !ask;
729 if (ask) {
730 KIO::JobUiDelegate uiDelegate;
731 uiDelegate.setWindow(parent);
732 doIt = uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::DefaultConfirmation);
733 }
734
735 if (doIt) {
737 KIO::DeleteJob *job = KIO::del(urls, flags);
738 KJobWidgets::setWindow(job, this);
740 return job;
741 }
742
743 return nullptr;
744}
745
747{
748 const QList<QUrl> urls = selectedItems().urlList();
749 if (urls.isEmpty()) {
750 KMessageBox::information(this, i18n("You did not select a file to delete."), i18n("Nothing to Delete"));
751 return;
752 }
753
754 using Iface = KIO::AskUserActionInterface;
755 auto *deleteJob = new KIO::DeleteOrTrashJob(urls, Iface::Delete, Iface::DefaultConfirmation, this);
756 deleteJob->start();
757}
758
759KIO::CopyJob *KDirOperator::trash(const KFileItemList &items, QWidget *parent, bool ask, bool showProgress)
760{
761 if (items.isEmpty()) {
762 KMessageBox::information(parent, i18n("You did not select a file to trash."), i18n("Nothing to Trash"));
763 return nullptr;
764 }
765
766 const QList<QUrl> urls = items.urlList();
767
768 bool doIt = !ask;
769 if (ask) {
770 KIO::JobUiDelegate uiDelegate;
771 uiDelegate.setWindow(parent);
772 doIt = uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Trash, KIO::JobUiDelegate::DefaultConfirmation);
773 }
774
775 if (doIt) {
777 KIO::CopyJob *job = KIO::trash(urls, flags);
778 KJobWidgets::setWindow(job, this);
780 return job;
781 }
782
783 return nullptr;
784}
785
787{
788 return d->m_previewGenerator;
789}
790
792{
793 d->m_inlinePreviewState = show ? KDirOperatorPrivate::ForcedToTrue : KDirOperatorPrivate::ForcedToFalse;
794}
795
797{
798 return d->m_showPreviews;
799}
800
802{
803 return d->m_iconSize;
804}
805
807{
808 d->m_isSaving = isSaving;
809}
810
812{
813 return d->m_isSaving;
814}
815
817{
818 if (d->m_itemView == nullptr) {
819 return;
820 }
821
822 const KFileItemList items = selectedItems();
823 if (items.isEmpty()) {
824 return;
825 }
826
827 KIO::RenameFileDialog *dialog = new KIO::RenameFileDialog(items, this);
828 connect(dialog, &KIO::RenameFileDialog::renamingFinished, this, [this](const QList<QUrl> &urls) {
829 d->assureVisibleSelection();
831 });
832
833 dialog->open();
834}
835
837{
838 if (d->m_itemView == nullptr) {
839 return;
840 }
841
844 return;
845 }
846
847 const QList<QUrl> urls = selectedItems().urlList();
848 if (urls.isEmpty()) {
849 KMessageBox::information(this, i18n("You did not select a file to trash."), i18n("Nothing to Trash"));
850 return;
851 }
852
853 using Iface = KIO::AskUserActionInterface;
854 auto *trashJob = new KIO::DeleteOrTrashJob(urls, Iface::Trash, Iface::DefaultConfirmation, this);
855 trashJob->start();
856}
857
859{
860 if (d->m_iconSize == value) {
861 return;
862 }
863
864 int size = value;
865 // Keep size range in sync with KFileWidgetPrivate::m_stdIconSizes
866 size = std::min(512, size);
867 size = std::max<int>(KIconLoader::SizeSmall, size);
868
869 d->m_iconSize = size;
870
871 if (!d->m_previewGenerator) {
872 return;
873 }
874
875 d->m_itemView->setIconSize(QSize(size, size));
876 d->m_previewGenerator->updateIcons();
877
879}
880
882{
883 resetCursor();
884 d->m_pendingMimeTypes.clear();
885 d->m_completion.clear();
886 d->m_dirCompletion.clear();
887 d->m_completeListDirty = true;
888 d->m_dirLister->stop();
889}
890
891void KDirOperator::setUrl(const QUrl &_newurl, bool clearforward)
892{
894 Utils::appendSlashToPath(newurl);
895
896 // already set
897 if (newurl.matches(d->m_currUrl, QUrl::StripTrailingSlash)) {
898 return;
899 }
900
901 if (!d->isSchemeSupported(newurl.scheme())) {
902 return;
903 }
904
905 if (!d->isReadable(newurl)) {
906 // maybe newurl is a file? check its parent directory
908 if (newurl.matches(d->m_currUrl, QUrl::StripTrailingSlash)) {
909 Q_EMIT urlEntered(newurl); // To remove the filename in pathCombo
910 return; // parent is current dir, nothing to do (fixes #173454, too)
911 }
912 KIO::StatJob *job = KIO::stat(newurl);
913 KJobWidgets::setWindow(job, this);
914 bool res = job->exec();
915
916 KIO::UDSEntry entry = job->statResult();
917 KFileItem i(entry, newurl);
918 if ((!res || !d->isReadable(newurl)) && i.isDir()) {
919 resetCursor();
920 KMessageBox::error(d->m_itemView,
921 i18n("The specified folder does not exist "
922 "or was not readable."));
923 return;
924 } else if (!i.isDir()) {
925 return;
926 }
927 }
928
929 if (clearforward) {
930 // autodelete should remove this one
931 d->m_backStack.push(new QUrl(d->m_currUrl));
932 qDeleteAll(d->m_forwardStack);
933 d->m_forwardStack.clear();
934 }
935
936 d->m_currUrl = newurl;
937
938 pathChanged();
939 Q_EMIT urlEntered(newurl);
940
941 // enable/disable actions
942 QAction *forwardAction = action(KDirOperator::Forward);
943 forwardAction->setEnabled(!d->m_forwardStack.isEmpty());
944
945 QAction *backAction = action(KDirOperator::Back);
946 backAction->setEnabled(!d->m_backStack.isEmpty());
947
948 QAction *upAction = action(KDirOperator::Up);
949 upAction->setEnabled(!isRoot());
950
951 d->openUrl(newurl);
952}
953
960
962{
963 pathChanged();
964 d->openUrl(d->m_currUrl, KDirLister::Reload);
965}
966
967bool KDirOperatorPrivate::isSchemeSupported(const QString &scheme) const
968{
969 return m_supportedSchemes.isEmpty() || m_supportedSchemes.contains(scheme);
970}
971
972bool KDirOperatorPrivate::openUrl(const QUrl &url, KDirLister::OpenUrlFlags flags)
973{
974 const bool result = KProtocolManager::supportsListing(url) && isSchemeSupported(url.scheme()) && m_dirLister->openUrl(url, flags);
975 if (!result) { // in that case, neither completed() nor canceled() will be emitted by KDL
976 slotCanceled();
977 }
978
979 return result;
980}
981
982int KDirOperatorPrivate::sortColumn() const
983{
984 int column = KDirModel::Name;
985 if (KFile::isSortByDate(m_sorting)) {
986 column = KDirModel::ModifiedTime;
987 } else if (KFile::isSortBySize(m_sorting)) {
988 column = KDirModel::Size;
989 } else if (KFile::isSortByType(m_sorting)) {
990 column = KDirModel::Type;
991 } else {
992 Q_ASSERT(KFile::isSortByName(m_sorting));
993 }
994
995 return column;
996}
997
998Qt::SortOrder KDirOperatorPrivate::sortOrder() const
999{
1000 return (m_sorting & QDir::Reversed) ? Qt::DescendingOrder : Qt::AscendingOrder;
1001}
1002
1003void KDirOperatorPrivate::updateSorting(QDir::SortFlags sort)
1004{
1005 // qDebug() << "changing sort flags from" << m_sorting << "to" << sort;
1006 if (sort == m_sorting) {
1007 return;
1008 }
1009
1010 m_sorting = sort;
1011 q->updateSortActions();
1012
1013 m_proxyModel->setSortFoldersFirst(m_sorting & QDir::DirsFirst);
1014 m_proxyModel->sort(sortColumn(), sortOrder());
1015
1016 // TODO: The headers from QTreeView don't take care about a sorting
1017 // change of the proxy model hence they must be updated the manually.
1018 // This is done here by a qobject_cast, but it would be nicer to:
1019 // - provide a signal 'sortingChanged()'
1020 // - connect KDirOperatorDetailView() with this signal and update the
1021 // header internally
1022 QTreeView *treeView = qobject_cast<QTreeView *>(m_itemView);
1023 if (treeView != nullptr) {
1024 QHeaderView *headerView = treeView->header();
1025 headerView->blockSignals(true);
1026 headerView->setSortIndicator(sortColumn(), sortOrder());
1027 headerView->blockSignals(false);
1028 }
1029
1030 assureVisibleSelection();
1031}
1032
1033// Protected
1035{
1036 if (d->m_itemView == nullptr) {
1037 return;
1038 }
1039
1040 d->m_pendingMimeTypes.clear();
1041 // d->fileView->clear(); TODO
1042 d->m_completion.clear();
1043 d->m_dirCompletion.clear();
1044
1045 // it may be, that we weren't ready at this time
1047
1048 // when KIO::Job emits finished, the slot will restore the cursor
1050
1051 if (!d->isReadable(d->m_currUrl)) {
1052 KMessageBox::error(d->m_itemView,
1053 i18n("The specified folder does not exist "
1054 "or was not readable."));
1055 if (d->m_backStack.isEmpty()) {
1056 home();
1057 } else {
1058 back();
1059 }
1060 }
1061}
1062
1063void KDirOperatorPrivate::slotRedirected(const QUrl &newURL)
1064{
1065 m_currUrl = newURL;
1066 m_pendingMimeTypes.clear();
1067 m_completion.clear();
1068 m_dirCompletion.clear();
1069 m_completeListDirty = true;
1070 Q_EMIT q->urlEntered(newURL);
1071}
1072
1073// Code pinched from kfm then hacked
1075{
1076 if (d->m_backStack.isEmpty()) {
1077 return;
1078 }
1079
1080 d->m_forwardStack.push(new QUrl(d->m_currUrl));
1081
1082 QUrl *s = d->m_backStack.pop();
1083 const QUrl newUrl = *s;
1084 delete s;
1085
1086 if (d->m_dirHighlighting) {
1088
1089 if (_url == d->m_currUrl.adjusted(QUrl::StripTrailingSlash) && !d->m_backStack.isEmpty()) {
1090 // e.g. started in a/b/c, cdUp() twice to "a", then back(), we highlight "c"
1091 d->m_lastUrl = *(d->m_backStack.top());
1092 } else {
1093 d->m_lastUrl = d->m_currUrl;
1094 }
1095 }
1096
1097 setUrl(newUrl, false);
1098}
1099
1100// Code pinched from kfm then hacked
1102{
1103 if (d->m_forwardStack.isEmpty()) {
1104 return;
1105 }
1106
1107 d->m_backStack.push(new QUrl(d->m_currUrl));
1108
1109 QUrl *s = d->m_forwardStack.pop();
1110 setUrl(*s, false);
1111 delete s;
1112}
1113
1115{
1116 return d->m_currUrl;
1117}
1118
1120{
1121 // Allow /d/c// to go up to /d/ instead of /d/c/
1122 QUrl tmp(d->m_currUrl.adjusted(QUrl::NormalizePathSegments));
1123
1124 if (d->m_dirHighlighting) {
1125 d->m_lastUrl = d->m_currUrl;
1126 }
1127
1128 setUrl(tmp.resolved(QUrl(QStringLiteral(".."))), true);
1129}
1130
1135
1137{
1138 d->m_dirLister->setNameFilter(QString());
1139 d->m_dirLister->clearMimeFilter();
1141}
1142
1144{
1145 d->m_dirLister->setNameFilter(filter);
1147}
1148
1150{
1151 return d->m_dirLister->nameFilter();
1152}
1153
1155{
1156 d->m_dirLister->setMimeFilter(mimetypes);
1158}
1159
1161{
1162 return d->m_dirLister->mimeFilters();
1163}
1164
1166{
1167 d->m_newFileMenu->setSupportedMimeTypes(mimeTypes);
1168}
1169
1171{
1172 return d->m_newFileMenu->supportedMimeTypes();
1173}
1174
1176{
1177 d->m_newFileMenu->setSelectDirWhenAlreadyExist(selectOnDirExists);
1178}
1179
1181{
1182 KToggleAction *previewAction = static_cast<KToggleAction *>(action(KDirOperator::ShowPreviewPanel));
1183
1184 bool hasPreviewSupport = false;
1185 KConfigGroup cg(KSharedConfig::openConfig(), ConfigGroup);
1186 if (cg.readEntry("Show Default Preview", true)) {
1187 hasPreviewSupport = d->checkPreviewInternal();
1188 }
1189
1190 previewAction->setEnabled(hasPreviewSupport);
1191 return hasPreviewSupport;
1192}
1193
1195{
1197
1198 d->m_newFileMenu->setWorkingDirectory(item.url());
1199 d->m_newFileMenu->checkUpToDate();
1200
1201 action(KDirOperator::New)->setEnabled(item.isDir());
1202
1203 Q_EMIT contextMenuAboutToShow(item, d->m_actionMenu->menu());
1204
1205 // Must be right before we call QMenu::exec(), otherwise we might remove
1206 // other non-related actions along with the open-with ones
1207 const QList<QAction *> openWithActions = d->insertOpenWithActions();
1208
1209 d->m_actionMenu->menu()->exec(pos);
1210
1211 // Remove the open-with actions, otherwise they would accumulate in the menu
1212 for (auto *action : openWithActions) {
1213 d->m_actionMenu->menu()->removeAction(action);
1214 }
1215}
1216
1217QList<QAction *> KDirOperatorPrivate::insertOpenWithActions()
1218{
1219 if (!m_showOpenWithActions) {
1220 return {};
1221 }
1222
1223 const QList<QAction *> beforeOpenWith = m_actionMenu->menu()->actions();
1224
1225 const KFileItemList items = q->selectedItems();
1226 if (!items.isEmpty()) {
1227 m_itemActions->setItemListProperties(KFileItemListProperties(items));
1228 const QList<QAction *> actions = m_actionMenu->menu()->actions();
1229 QAction *before = !actions.isEmpty() ? actions.at(0) : nullptr;
1230 m_itemActions->insertOpenWithActionsTo(before, m_actionMenu->menu(), QStringList());
1231 }
1232
1233 // Get the list of the added open-with actions
1234 QList<QAction *> toRemove = m_actionMenu->menu()->actions();
1235 auto it = std::remove_if(toRemove.begin(), toRemove.end(), [beforeOpenWith](QAction *a) {
1236 return beforeOpenWith.contains(a);
1237 });
1238 toRemove.erase(it, toRemove.end());
1239
1240 return toRemove;
1241}
1242
1244{
1245 d->m_showOpenWithActions = enable;
1246}
1247
1248void KDirOperator::changeEvent(QEvent *event)
1249{
1251}
1252
1253bool KDirOperator::eventFilter(QObject *watched, QEvent *event)
1254{
1255 // If we are not hovering any items, check if there is a current index
1256 // set. In that case, we show the preview of that item.
1257 switch (event->type()) {
1258 case QEvent::TouchBegin:
1259 d->m_isTouchEvent = true;
1260 break;
1261 case QEvent::MouseMove: {
1262 if (d->m_isTouchEvent) {
1263 return true;
1264 }
1265
1266 const QModelIndex hoveredIndex = d->m_itemView->indexAt(d->m_itemView->viewport()->mapFromGlobal(QCursor::pos()));
1267 if (hoveredIndex.isValid()) {
1268 KFileItemSelectionEmblem(d->m_itemView, hoveredIndex, this).updateSelectionEmblemRectForIndex(iconSize());
1269 }
1270
1271 if (d->m_preview && !d->m_preview->isHidden()) {
1272 if (d->m_lastHoveredIndex == hoveredIndex) {
1273 return QWidget::eventFilter(watched, event);
1274 }
1275
1276 d->m_lastHoveredIndex = hoveredIndex;
1277
1278 const QModelIndex currentIndex = d->m_itemView->selectionModel() ? d->m_itemView->selectionModel()->currentIndex() : QModelIndex();
1279
1280 if (!hoveredIndex.isValid() && currentIndex.isValid() && (d->m_lastHoveredIndex != currentIndex)) {
1281 const KFileItem item = d->m_itemView->model()->data(currentIndex, KDirModel::FileItemRole).value<KFileItem>();
1282 if (!item.isNull()) {
1283 d->m_preview->showPreview(item.url());
1284 }
1285 }
1286 }
1287 break;
1288 }
1291 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
1292 if (mouseEvent) {
1293 // Navigate and then discard the event so it doesn't select an item on the directory navigated to.
1294 switch (mouseEvent->button()) {
1295 case Qt::BackButton:
1296 back();
1297 return true;
1298 case Qt::ForwardButton:
1299 forward();
1300 return true;
1301 default:
1302 break;
1303 }
1304 }
1305 break;
1306 }
1308 if (d->m_preview != nullptr && !d->m_preview->isHidden()) {
1309 const QModelIndex hoveredIndex = d->m_itemView->indexAt(d->m_itemView->viewport()->mapFromGlobal(QCursor::pos()));
1310 const QModelIndex focusedIndex = d->m_itemView->selectionModel() ? d->m_itemView->selectionModel()->currentIndex() : QModelIndex();
1311
1312 if (((!focusedIndex.isValid()) || !d->m_itemView->selectionModel()->isSelected(focusedIndex)) && (!hoveredIndex.isValid())) {
1313 d->m_preview->clearPreview();
1314 }
1315 }
1316
1317 d->m_isTouchEvent = false;
1318 if (d->m_isTouchDrag) {
1319 d->m_isTouchDrag = false;
1320 return true;
1321 }
1322
1323 break;
1324 }
1325 case QEvent::HoverLeave: {
1326 if (d->m_preview && !d->m_preview->isHidden()) {
1327 const QModelIndex currentIndex = d->m_itemView->selectionModel() ? d->m_itemView->selectionModel()->currentIndex() : QModelIndex();
1328
1329 if (currentIndex.isValid() && d->m_itemView->selectionModel()->isSelected(currentIndex)) {
1330 const KFileItem item = d->m_itemView->model()->data(currentIndex, KDirModel::FileItemRole).value<KFileItem>();
1331 if (!item.isNull()) {
1332 d->m_preview->showPreview(item.url());
1333 }
1334 }
1335 }
1336 break;
1337 }
1338 case QEvent::Wheel: {
1339 QWheelEvent *evt = static_cast<QWheelEvent *>(event);
1340 if (evt->modifiers() & Qt::ControlModifier) {
1341 if (evt->angleDelta().y() > 0) {
1342 setIconSize(d->m_iconSize + 10);
1343 } else {
1344 setIconSize(d->m_iconSize - 10);
1345 }
1346 return true;
1347 }
1348 break;
1349 }
1350 case QEvent::DragEnter: {
1351 // Accepts drops of one file or folder only
1352 QDragEnterEvent *evt = static_cast<QDragEnterEvent *>(event);
1354
1355 // only one file/folder can be dropped at the moment
1356 if (urls.size() != 1) {
1357 evt->ignore();
1358
1359 } else {
1360 // MIME type filtering
1361 bool mimeFilterPass = true;
1362 const QStringList mimeFilters = d->m_dirLister->mimeFilters();
1363
1364 if (mimeFilters.size() > 1) {
1365 mimeFilterPass = false;
1366 const QUrl &url = urls.constFirst();
1367
1368 QMimeDatabase mimeDataBase;
1369 QMimeType fileMimeType = mimeDataBase.mimeTypeForUrl(url);
1370
1371 QRegularExpression regex;
1372 for (const auto &mimeFilter : mimeFilters) {
1373 regex.setPattern(mimeFilter);
1374 if (regex.match(fileMimeType.name()).hasMatch()) { // matches!
1375 mimeFilterPass = true;
1376 break;
1377 }
1378 }
1379 }
1380
1381 event->setAccepted(mimeFilterPass);
1382 }
1383
1384 return true;
1385 }
1386 case QEvent::Drop: {
1387 QDropEvent *evt = static_cast<QDropEvent *>(event);
1389
1390 const QUrl &url = urls.constFirst();
1391
1392 // stat the url to get details
1393 KIO::StatJob *job = KIO::stat(url, KIO::HideProgressInfo);
1394 job->exec();
1395
1396 setFocus();
1397
1398 const KIO::UDSEntry entry = job->statResult();
1399
1400 if (entry.isDir()) {
1401 // if this was a directory
1402 setUrl(url, false);
1403 } else {
1404 // if the current url is not known
1405 if (d->m_dirLister->findByUrl(url).isNull()) {
1406 setUrl(url.adjusted(QUrl::RemoveFilename), false);
1407
1408 // Will set the current item once loading has finished
1409 auto urlSetterClosure = [this, url]() {
1411 QObject::disconnect(d->m_connection);
1412 };
1413 d->m_connection = connect(this, &KDirOperator::finishedLoading, this, urlSetterClosure);
1414 } else {
1416 }
1417 }
1418 evt->accept();
1419 return true;
1420 }
1421 case QEvent::KeyPress: {
1422 QKeyEvent *evt = static_cast<QKeyEvent *>(event);
1423 if (evt->key() == Qt::Key_Return || evt->key() == Qt::Key_Enter) {
1424 // when no elements are selected and Return/Enter is pressed
1425 // emit keyEnterReturnPressed
1426 // let activated event be emitted by subsequent QAbstractItemView::keyPress otherwise
1427 if (!d->m_itemView->currentIndex().isValid()) {
1429 evt->accept();
1430 return true;
1431 }
1432 }
1433 // Only use tab key to escape the view navigation
1434 if (evt->key() == Qt::Key_Tab) {
1435 d->m_keyNavigation = false;
1436 d->slotSelectionChanged();
1437 // When saving we need to return here,
1438 // otherwise we skip over the next item with our tab press
1439 // since we focus on that item in slotSelectionChanged
1440 if (d->m_isSaving) {
1441 return true;
1442 }
1443 } else {
1444 d->m_keyNavigation = true;
1445 }
1446 break;
1447 }
1448 case QEvent::Resize: {
1449 /* clang-format off */
1450 if (watched == d->m_itemView->viewport()
1451 && d->m_itemView->horizontalScrollBar()
1452 && d->m_progressBar->parent() == this /* it could have been reparented to a statusbar */) { /* clang-format on */
1453 if (d->m_itemView->horizontalScrollBar()->isVisible()) {
1454 // Show the progress bar above the horizontal scrollbar that may be visible
1455 // in compact view
1456 QPoint progressBarPos = d->progressBarPos();
1457 progressBarPos.ry() -= d->m_itemView->horizontalScrollBar()->height();
1458 d->m_progressBar->move(progressBarPos);
1459 } else {
1460 d->m_progressBar->move(d->progressBarPos());
1461 }
1462 }
1463 break;
1464 }
1465 default:
1466 break;
1467 }
1468
1469 return QWidget::eventFilter(watched, event);
1470}
1471
1472bool KDirOperatorPrivate::checkPreviewInternal() const
1473{
1474 const QStringList supported = KIO::PreviewJob::supportedMimeTypes();
1475 // no preview support for directories?
1476 if (q->dirOnlyMode() && !supported.contains(QLatin1String("inode/directory"))) {
1477 return false;
1478 }
1479
1480 const QStringList mimeTypes = m_dirLister->mimeFilters();
1481 const QStringList nameFilters = m_dirLister->nameFilter().split(QLatin1Char(' '), Qt::SkipEmptyParts);
1482
1483 if (mimeTypes.isEmpty() && nameFilters.isEmpty() && !supported.isEmpty()) {
1484 return true;
1485 } else {
1486 QMimeDatabase db;
1487 QRegularExpression re;
1488
1489 if (!mimeTypes.isEmpty()) {
1490 for (const QString &str : supported) {
1491 // wildcard matching because the "mimetype" can be "image/*"
1493
1494 if (mimeTypes.indexOf(re) != -1) { // matches! -> we want previews
1495 return true;
1496 }
1497 }
1498 }
1499
1500 if (!nameFilters.isEmpty()) {
1501 // find the MIME types of all the filter-patterns
1502 for (const QString &filter : nameFilters) {
1503 if (filter == QLatin1Char('*')) {
1504 return true;
1505 }
1506
1507 const QMimeType mt = db.mimeTypeForFile(filter, QMimeDatabase::MatchExtension /*fast mode, no file contents exist*/);
1508 if (!mt.isValid()) {
1509 continue;
1510 }
1511 const QString mime = mt.name();
1512
1513 for (const QString &str : supported) {
1514 // the "mimetypes" we get from the PreviewJob can be "image/*"
1515 // so we need to check in wildcard mode
1517 if (re.match(mime).hasMatch()) {
1518 return true;
1519 }
1520 }
1521 }
1522 }
1523 }
1524
1525 return false;
1526}
1527
1529{
1530 QAbstractItemView *itemView = nullptr;
1531 if (KFile::isDetailView(viewKind) || KFile::isTreeView(viewKind) || KFile::isDetailTreeView(viewKind)) {
1532 KDirOperatorDetailView *detailView = new KDirOperatorDetailView(this, parent);
1533 detailView->setViewMode(viewKind);
1534 itemView = detailView;
1535 } else {
1536 itemView = new KDirOperatorIconView(this, parent, decorationPosition());
1537 }
1538
1539 return itemView;
1540}
1541
1542void KDirOperator::setAcceptDrops(bool acceptsDrops)
1543{
1544 QWidget::setAcceptDrops(acceptsDrops);
1545 if (view()) {
1546 view()->setAcceptDrops(acceptsDrops);
1547 if (acceptsDrops) {
1548 view()->installEventFilter(this);
1549 } else {
1550 view()->removeEventFilter(this);
1551 }
1552 }
1553}
1554
1556{
1557 d->m_dropOptions = options;
1558 // TODO:
1559 // if (d->fileView)
1560 // d->fileView->setDropOptions(options);
1561}
1562
1563void KDirOperator::setViewMode(KFile::FileView viewKind)
1564{
1565 bool preview = (KFile::isPreviewInfo(viewKind) || KFile::isPreviewContents(viewKind));
1566
1567 if (viewKind == KFile::Default) {
1568 if (KFile::isDetailView((KFile::FileView)d->m_defaultView)) {
1569 viewKind = KFile::Detail;
1570 } else if (KFile::isTreeView((KFile::FileView)d->m_defaultView)) {
1571 viewKind = KFile::Tree;
1572 } else if (KFile::isDetailTreeView((KFile::FileView)d->m_defaultView)) {
1573 viewKind = KFile::DetailTree;
1574 } else {
1575 viewKind = KFile::Simple;
1576 }
1577
1578 const KFile::FileView defaultViewKind = static_cast<KFile::FileView>(d->m_defaultView);
1579 preview = (KFile::isPreviewInfo(defaultViewKind) || KFile::isPreviewContents(defaultViewKind)) && action(KDirOperator::ShowPreviewPanel)->isEnabled();
1580 }
1581
1582 d->m_viewKind = static_cast<int>(viewKind);
1583 viewKind = static_cast<KFile::FileView>(d->m_viewKind);
1584
1585 QAbstractItemView *newView = createView(this, viewKind);
1586 setViewInternal(newView);
1587
1588 if (acceptDrops()) {
1589 newView->setAcceptDrops(true);
1590 newView->installEventFilter(this);
1591 }
1592
1593 d->togglePreview(preview);
1594}
1595
1596KFile::FileView KDirOperator::viewMode() const
1597{
1598 return static_cast<KFile::FileView>(d->m_viewKind);
1599}
1600
1602{
1603 return d->m_itemView;
1604}
1605
1607{
1608 return d->m_mode;
1609}
1610
1612{
1613 if (d->m_mode == mode) {
1614 return;
1615 }
1616
1617 const bool isDirOnlyChanged = dirOnlyMode(d->m_mode) != dirOnlyMode(mode);
1618
1619 d->m_mode = mode;
1620
1621 d->m_dirLister->setDirOnlyMode(dirOnlyMode());
1622
1623 // When KFile::Directory mode changes, we need to update the dir,
1624 // otherwise initially we would be showing dirs and files even when
1625 // dirOnlyMode() is true
1626 if (isDirOnlyChanged) {
1627 updateDir();
1628 }
1629
1630 // reset the view with the different mode
1631 if (d->m_itemView != nullptr) {
1632 setViewMode(static_cast<KFile::FileView>(d->m_viewKind));
1633 }
1634}
1635
1636void KDirOperator::setViewInternal(QAbstractItemView *view)
1637{
1638 if (view == d->m_itemView) {
1639 return;
1640 }
1641
1642 // TODO: do a real timer and restart it after that
1643 d->m_pendingMimeTypes.clear();
1644 const bool listDir = (d->m_itemView == nullptr);
1645
1646 if (d->m_itemView) {
1647 d->m_itemView->viewport()->removeEventFilter(this);
1648 }
1649 QScroller *scroller = QScroller::scroller(view->viewport());
1650 QScrollerProperties scrollerProp;
1652 scroller->setScrollerProperties(scrollerProp);
1653 scroller->grabGesture(view->viewport());
1654 connect(scroller, &QScroller::stateChanged, this, [this](const QScroller::State newState) {
1655 if (newState == QScroller::Inactive) {
1656 d->m_isTouchEvent = false;
1657 } else if (newState == QScroller::Dragging) {
1658 d->m_isTouchDrag = true;
1659 }
1660 });
1661 view->viewport()->grabGesture(Qt::TapGesture);
1662 view->setAttribute(Qt::WA_AcceptTouchEvents);
1663
1664 if (d->m_mode & KFile::Files) {
1665 view->setSelectionMode(QAbstractItemView::ExtendedSelection);
1666 } else {
1667 view->setSelectionMode(QAbstractItemView::SingleSelection);
1668 }
1669
1670 QItemSelectionModel *selectionModel = nullptr;
1671 if ((d->m_itemView != nullptr) && d->m_itemView->selectionModel()->hasSelection()) {
1672 // remember the selection of the current item view and apply this selection
1673 // to the new view later
1674 const QItemSelection selection = d->m_itemView->selectionModel()->selection();
1675 selectionModel = new QItemSelectionModel(d->m_proxyModel, this);
1676 selectionModel->select(selection, QItemSelectionModel::Select);
1677 }
1678
1679 setFocusProxy(nullptr);
1680 delete d->m_itemView;
1681 d->m_itemView = view;
1682 d->m_itemView->setModel(d->m_proxyModel);
1683 setFocusProxy(d->m_itemView);
1684
1685 d->m_itemView->viewport()->setObjectName(QStringLiteral("d->itemview_viewport"));
1686 view->viewport()->installEventFilter(this);
1687
1688 KFileItemDelegate *delegate = new KFileItemDelegate(d->m_itemView);
1689 d->m_itemView->setItemDelegate(delegate);
1690 d->m_itemView->viewport()->setAttribute(Qt::WA_Hover);
1691 d->m_itemView->setContextMenuPolicy(Qt::CustomContextMenu);
1692 d->m_itemView->setMouseTracking(true);
1693 // d->itemView->setDropOptions(d->dropOptions);
1694
1695 // first push our settings to the view, then listen for changes from the view
1696 QTreeView *treeView = qobject_cast<QTreeView *>(d->m_itemView);
1697 if (treeView) {
1698 QHeaderView *headerView = treeView->header();
1699 headerView->setSortIndicator(d->sortColumn(), d->sortOrder());
1700 connect(headerView, &QHeaderView::sortIndicatorChanged, this, [this](int logicalIndex, Qt::SortOrder order) {
1701 d->synchronizeSortingState(logicalIndex, order);
1702 });
1703 }
1704
1705 connect(d->m_itemView, &QAbstractItemView::activated, this, [this](QModelIndex index) {
1706 d->slotActivated(index);
1707 });
1708
1709 connect(d->m_itemView, &QAbstractItemView::customContextMenuRequested, this, [this](QPoint pos) {
1710 d->openContextMenu(pos);
1711 });
1712
1713 connect(d->m_itemView, &QAbstractItemView::entered, this, [this](QModelIndex index) {
1714 d->triggerPreview(index);
1715 });
1716
1717 d->m_splitter->insertWidget(0, d->m_itemView);
1718
1719 d->m_splitter->resize(size());
1720 d->m_itemView->show();
1721
1722 if (listDir) {
1724 d->openUrl(d->m_currUrl);
1725 }
1726
1727 if (selectionModel != nullptr) {
1728 d->m_itemView->setSelectionModel(selectionModel);
1729 auto assureVisFunc = [this]() {
1730 d->assureVisibleSelection();
1731 };
1732 QMetaObject::invokeMethod(this, assureVisFunc, Qt::QueuedConnection);
1733 }
1734
1735 connect(d->m_itemView->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](QModelIndex index) {
1736 d->triggerPreview(index);
1737 });
1738 connect(d->m_itemView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this]() {
1739 d->slotSelectionChanged();
1740 });
1741
1742 // if we cannot cast it to a QListView, disable the "Icon Position" menu. Note that this check
1743 // needs to be done here, and not in createView, since we can be set an external view
1744 d->m_decorationMenu->setEnabled(qobject_cast<QListView *>(d->m_itemView));
1745
1746 d->m_shouldFetchForItems = qobject_cast<QTreeView *>(view);
1747 if (d->m_shouldFetchForItems) {
1748 connect(d->m_dirModel, &KDirModel::expand, this, [this](QModelIndex index) {
1749 d->slotExpandToUrl(index);
1750 });
1751 } else {
1752 d->m_itemsToBeSetAsCurrent.clear();
1753 }
1754
1755 const bool previewForcedToTrue = d->m_inlinePreviewState == KDirOperatorPrivate::ForcedToTrue;
1756 const bool previewShown = d->m_inlinePreviewState == KDirOperatorPrivate::NotForced ? d->m_showPreviews : previewForcedToTrue;
1757 d->m_itemView->setIconSize(previewForcedToTrue ? QSize(KIconLoader::SizeHuge, KIconLoader::SizeHuge) : QSize(d->m_iconSize, d->m_iconSize));
1758 d->m_previewGenerator = new KFilePreviewGenerator(d->m_itemView);
1759 d->m_previewGenerator->setPreviewShown(previewShown);
1760 action(KDirOperator::ShowPreview)->setChecked(previewShown);
1761
1762 // ensure we change everything needed
1763 d->slotChangeDecorationPosition();
1765
1767
1768 const int zoom = previewForcedToTrue ? KIconLoader::SizeHuge : d->iconSizeForViewType(view);
1769
1770 // this will make d->m_iconSize be updated, since setIconSize slot will be called
1772}
1773
1775{
1776 if (lister == d->m_dirLister) { // sanity check
1777 return;
1778 }
1779
1780 delete d->m_dirModel;
1781 d->m_dirModel = nullptr;
1782
1783 delete d->m_proxyModel;
1784 d->m_proxyModel = nullptr;
1785
1786 // delete d->m_dirLister; // deleted by KDirModel already, which took ownership
1787 d->m_dirLister = lister;
1788
1789 d->m_dirModel = new KDirModel(this);
1790 d->m_dirModel->setDirLister(d->m_dirLister);
1791 d->m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory);
1792
1793 d->m_shouldFetchForItems = qobject_cast<QTreeView *>(d->m_itemView);
1794 if (d->m_shouldFetchForItems) {
1795 connect(d->m_dirModel, &KDirModel::expand, this, [this](QModelIndex index) {
1796 d->slotExpandToUrl(index);
1797 });
1798 } else {
1799 d->m_itemsToBeSetAsCurrent.clear();
1800 }
1801
1802 d->m_proxyModel = new KDirSortFilterProxyModel(this);
1803 d->m_proxyModel->setSourceModel(d->m_dirModel);
1804
1805 d->m_dirLister->setDelayedMimeTypes(true);
1806
1807 QWidget *mainWidget = topLevelWidget();
1808 d->m_dirLister->setMainWindow(mainWidget);
1809 // qDebug() << "mainWidget=" << mainWidget;
1810
1811 connect(d->m_dirLister, &KCoreDirLister::percent, this, [this](int percent) {
1812 d->slotProgress(percent);
1813 });
1814 connect(d->m_dirLister, &KCoreDirLister::started, this, [this]() {
1815 d->slotStarted();
1816 });
1817 connect(d->m_dirLister, qOverload<>(&KCoreDirLister::completed), this, [this]() {
1818 d->slotIOFinished();
1819 });
1820 connect(d->m_dirLister, qOverload<>(&KCoreDirLister::canceled), this, [this]() {
1821 d->slotCanceled();
1822 });
1823 connect(d->m_dirLister, &KCoreDirLister::jobError, this, [this]() {
1824 d->slotIOFinished();
1825 });
1826 connect(d->m_dirLister, &KCoreDirLister::redirection, this, [this](const QUrl &, const QUrl &newUrl) {
1827 d->slotRedirected(newUrl);
1828 });
1829 connect(d->m_dirLister, &KCoreDirLister::newItems, this, [this]() {
1830 d->slotItemsChanged();
1831 });
1832 connect(d->m_dirLister, &KCoreDirLister::itemsDeleted, this, [this]() {
1833 d->slotItemsChanged();
1834 });
1835 connect(d->m_dirLister, qOverload<>(&KCoreDirLister::clear), this, [this]() {
1836 d->slotItemsChanged();
1837 });
1838}
1839
1841{
1842 setUrl(item.targetUrl(), true);
1843}
1844
1846{
1848
1849 Q_EMIT fileSelected(item);
1850 d->m_keyNavigation = false;
1851}
1852
1854{
1855 if ((d->m_preview != nullptr && !d->m_preview->isHidden()) && !item.isNull()) {
1856 d->m_preview->showPreview(item.url());
1857 }
1858
1859 Q_EMIT fileHighlighted(item, d->m_keyNavigation);
1860 d->m_keyNavigation = false;
1861}
1862
1864{
1865 // qDebug();
1866
1867 KFileItem item = d->m_dirLister->findByUrl(url);
1868 if (d->m_shouldFetchForItems && item.isNull()) {
1869 d->m_itemsToBeSetAsCurrent << url;
1870
1871 if (d->m_viewKind == KFile::DetailTree) {
1872 d->m_dirModel->expandToUrl(url);
1873 }
1874
1875 return;
1876 }
1877
1878 setCurrentItem(item);
1879}
1880
1882{
1883 // qDebug();
1884
1885 if (!d->m_itemView) {
1886 return;
1887 }
1888
1889 QItemSelectionModel *selModel = d->m_itemView->selectionModel();
1890 if (selModel) {
1891 selModel->clear();
1892 if (!item.isNull()) {
1893 const QModelIndex dirIndex = d->m_dirModel->indexForItem(item);
1894 const QModelIndex proxyIndex = d->m_proxyModel->mapFromSource(dirIndex);
1895 selModel->setCurrentIndex(proxyIndex, QItemSelectionModel::Select);
1896 }
1897 }
1898}
1899
1901{
1902 // qDebug();
1903
1904 if (!d->m_itemView) {
1905 return;
1906 }
1907
1908 KFileItemList itemList;
1909 for (const QUrl &url : urls) {
1910 KFileItem item = d->m_dirLister->findByUrl(url);
1911 if (d->m_shouldFetchForItems && item.isNull()) {
1912 d->m_itemsToBeSetAsCurrent << url;
1913
1914 if (d->m_viewKind == KFile::DetailTree) {
1915 d->m_dirModel->expandToUrl(url);
1916 }
1917
1918 continue;
1919 }
1920
1921 itemList << item;
1922 }
1923
1924 setCurrentItems(itemList);
1925}
1926
1928{
1929 // qDebug();
1930
1931 if (d->m_itemView == nullptr) {
1932 return;
1933 }
1934
1935 QItemSelectionModel *selModel = d->m_itemView->selectionModel();
1936 if (selModel) {
1937 selModel->clear();
1938 QModelIndex proxyIndex;
1939 for (const KFileItem &item : items) {
1940 if (!item.isNull()) {
1941 const QModelIndex dirIndex = d->m_dirModel->indexForItem(item);
1942 proxyIndex = d->m_proxyModel->mapFromSource(dirIndex);
1943 selModel->select(proxyIndex, QItemSelectionModel::Select);
1944 }
1945 }
1946 if (proxyIndex.isValid()) {
1947 selModel->setCurrentIndex(proxyIndex, QItemSelectionModel::NoUpdate);
1948 }
1949 }
1950}
1951
1953{
1954 if (string.isEmpty()) {
1955 d->m_itemView->selectionModel()->clear();
1956 return QString();
1957 }
1958
1960 return d->m_completion.makeCompletion(string);
1961}
1962
1964{
1965 if (string.isEmpty()) {
1966 d->m_itemView->selectionModel()->clear();
1967 return QString();
1968 }
1969
1971 return d->m_dirCompletion.makeCompletion(string);
1972}
1973
1975{
1976 if (d->m_itemView == nullptr) {
1977 return;
1978 }
1979
1980 if (d->m_completeListDirty) { // create the list of all possible completions
1981 const KFileItemList itemList = d->m_dirLister->items();
1982 for (const KFileItem &item : itemList) {
1983 d->m_completion.addItem(item.name());
1984 if (item.isDir()) {
1985 d->m_dirCompletion.addItem(item.name());
1986 }
1987 }
1988 d->m_completeListDirty = false;
1989 }
1990}
1991
1993{
1994 QUrl url(match);
1995 if (url.isRelative()) {
1996 url = d->m_currUrl.resolved(url);
1997 }
1999 Q_EMIT completion(match);
2000}
2001
2003{
2004 d->m_actionMenu = new KActionMenu(i18n("Menu"), this);
2005 d->m_actions[PopupMenu] = d->m_actionMenu;
2006
2008 d->m_actions[Up] = upAction;
2009 upAction->setText(i18n("Parent Folder"));
2010
2012 d->m_actions[Back] = backAction;
2013 auto backShortcuts = backAction->shortcuts();
2014 backShortcuts << Qt::Key_Backspace;
2015 backAction->setShortcuts(backShortcuts);
2016 backAction->setToolTip(i18nc("@info", "Go back"));
2017
2019 d->m_actions[Forward] = forwardAction;
2020 forwardAction->setToolTip(i18nc("@info", "Go forward"));
2021
2023 d->m_actions[Home] = homeAction;
2024 homeAction->setText(i18n("Home Folder"));
2025
2027 d->m_actions[Reload] = reloadAction;
2028 reloadAction->setText(i18n("Reload"));
2030
2031 auto *mkdirAction = new QAction(i18nc("@action", "New Folder…"), this);
2032 d->m_actions[NewFolder] = mkdirAction;
2033 mkdirAction->setIcon(QIcon::fromTheme(QStringLiteral("folder-new")));
2034 connect(mkdirAction, &QAction::triggered, this, [this]() {
2035 mkdir();
2036 });
2037
2038 QAction *rename = KStandardActions::renameFile(this, &KDirOperator::renameSelected, this);
2039 d->m_actions[Rename] = rename;
2040
2041 QAction *trash = new QAction(i18n("Move to Trash"), this);
2042 d->m_actions[Trash] = trash;
2043 trash->setIcon(QIcon::fromTheme(QStringLiteral("user-trash")));
2044 trash->setShortcut(Qt::Key_Delete);
2046
2047 QAction *action = new QAction(i18n("Delete"), this);
2048 d->m_actions[Delete] = action;
2049 action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
2050 action->setShortcut(Qt::SHIFT | Qt::Key_Delete);
2052
2053 // the sort menu actions
2054 KActionMenu *sortMenu = new KActionMenu(i18n("Sorting"), this);
2055 d->m_actions[SortMenu] = sortMenu;
2056 sortMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-sort")));
2058
2059 KToggleAction *byNameAction = new KToggleAction(i18n("Sort by Name"), this);
2060 d->m_actions[SortByName] = byNameAction;
2061 connect(byNameAction, &QAction::triggered, this, [this]() {
2062 d->slotSortByName();
2063 });
2064
2065 KToggleAction *bySizeAction = new KToggleAction(i18n("Sort by Size"), this);
2066 d->m_actions[SortBySize] = bySizeAction;
2067 connect(bySizeAction, &QAction::triggered, this, [this]() {
2068 d->slotSortBySize();
2069 });
2070
2071 KToggleAction *byDateAction = new KToggleAction(i18n("Sort by Date"), this);
2072 d->m_actions[SortByDate] = byDateAction;
2073 connect(byDateAction, &QAction::triggered, this, [this]() {
2074 d->slotSortByDate();
2075 });
2076
2077 KToggleAction *byTypeAction = new KToggleAction(i18n("Sort by Type"), this);
2078 d->m_actions[SortByType] = byTypeAction;
2079 connect(byTypeAction, &QAction::triggered, this, [this]() {
2080 d->slotSortByType();
2081 });
2082
2083 QActionGroup *sortOrderGroup = new QActionGroup(this);
2084 sortOrderGroup->setExclusive(true);
2085
2086 KToggleAction *ascendingAction = new KToggleAction(i18n("Ascending"), this);
2087 d->m_actions[SortAscending] = ascendingAction;
2088 ascendingAction->setActionGroup(sortOrderGroup);
2089 connect(ascendingAction, &QAction::triggered, this, [this]() {
2090 this->d->slotSortReversed(false);
2091 });
2092
2093 KToggleAction *descendingAction = new KToggleAction(i18n("Descending"), this);
2094 d->m_actions[SortDescending] = descendingAction;
2095 descendingAction->setActionGroup(sortOrderGroup);
2096 connect(descendingAction, &QAction::triggered, this, [this]() {
2097 this->d->slotSortReversed(true);
2098 });
2099
2100 KToggleAction *dirsFirstAction = new KToggleAction(i18n("Folders First"), this);
2101 d->m_actions[SortFoldersFirst] = dirsFirstAction;
2102 connect(dirsFirstAction, &QAction::triggered, this, [this]() {
2103 d->slotToggleDirsFirst();
2104 });
2105
2106 KToggleAction *hiddenFilesLastAction = new KToggleAction(i18n("Hidden Files Last"), this);
2107 d->m_actions[SortHiddenFilesLast] = hiddenFilesLastAction;
2108 connect(hiddenFilesLastAction, &QAction::toggled, this, [this](bool checked) {
2109 d->m_proxyModel->setSortHiddenFilesLast(checked);
2110 });
2111
2112 // View modes that match those of Dolphin
2113 KToggleAction *iconsViewAction = new KToggleAction(i18n("Icons View"), this);
2114 d->m_actions[ViewIconsView] = iconsViewAction;
2115 iconsViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons")));
2116 connect(iconsViewAction, &QAction::triggered, this, [this]() {
2117 d->slotIconsView();
2118 });
2119
2120 KToggleAction *compactViewAction = new KToggleAction(i18n("Compact View"), this);
2121 d->m_actions[ViewCompactView] = compactViewAction;
2122 compactViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details")));
2123 connect(compactViewAction, &QAction::triggered, this, [this]() {
2124 d->slotCompactView();
2125 });
2126
2127 KToggleAction *detailsViewAction = new KToggleAction(i18n("Details View"), this);
2128 d->m_actions[ViewDetailsView] = detailsViewAction;
2129 detailsViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
2130 connect(detailsViewAction, &QAction::triggered, this, [this]() {
2131 d->slotDetailsView();
2132 });
2133
2134 QActionGroup *viewModeGroup = new QActionGroup(this);
2135 viewModeGroup->setExclusive(true);
2136 iconsViewAction->setActionGroup(viewModeGroup);
2137 compactViewAction->setActionGroup(viewModeGroup);
2138 detailsViewAction->setActionGroup(viewModeGroup);
2139
2140 QActionGroup *sortGroup = new QActionGroup(this);
2141 byNameAction->setActionGroup(sortGroup);
2142 bySizeAction->setActionGroup(sortGroup);
2143 byDateAction->setActionGroup(sortGroup);
2144 byTypeAction->setActionGroup(sortGroup);
2145
2146 d->m_decorationMenu = new KActionMenu(i18n("Icon Position"), this);
2147 d->m_actions[DecorationMenu] = d->m_decorationMenu;
2148
2149 d->m_leftAction = new KToggleAction(i18n("Next to File Name"), this);
2150 d->m_actions[DecorationAtLeft] = d->m_leftAction;
2151 connect(d->m_leftAction, &QAction::triggered, this, [this]() {
2152 d->slotChangeDecorationPosition();
2153 });
2154
2155 KToggleAction *topAction = new KToggleAction(i18n("Above File Name"), this);
2156 d->m_actions[DecorationAtTop] = topAction;
2157 connect(topAction, &QAction::triggered, this, [this]() {
2158 d->slotChangeDecorationPosition();
2159 });
2160
2161 d->m_decorationMenu->addAction(d->m_leftAction);
2162 d->m_decorationMenu->addAction(topAction);
2163
2164 QActionGroup *decorationGroup = new QActionGroup(this);
2165 decorationGroup->setExclusive(true);
2166 d->m_leftAction->setActionGroup(decorationGroup);
2167 topAction->setActionGroup(decorationGroup);
2168
2169 KToggleAction *shortAction = new KToggleAction(i18n("Short View"), this);
2170 d->m_actions[ShortView] = shortAction;
2171 shortAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons")));
2172 connect(shortAction, &QAction::triggered, this, [this]() {
2173 d->slotSimpleView();
2174 });
2175
2176 KToggleAction *detailedAction = new KToggleAction(i18n("Detailed View"), this);
2177 d->m_actions[DetailedView] = detailedAction;
2178 detailedAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details")));
2179 connect(detailedAction, &QAction::triggered, this, [this]() {
2180 d->slotDetailedView();
2181 });
2182
2183 KToggleAction *treeAction = new KToggleAction(i18n("Tree View"), this);
2184 d->m_actions[TreeView] = treeAction;
2185 treeAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
2186 connect(treeAction, &QAction::triggered, this, [this]() {
2187 d->slotTreeView();
2188 });
2189
2190 KToggleAction *detailedTreeAction = new KToggleAction(i18n("Detailed Tree View"), this);
2191 d->m_actions[DetailedTreeView] = detailedTreeAction;
2192 detailedTreeAction->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
2193 connect(detailedTreeAction, &QAction::triggered, this, [this]() {
2194 d->slotDetailedTreeView();
2195 });
2196
2197 QActionGroup *viewGroup = new QActionGroup(this);
2198 shortAction->setActionGroup(viewGroup);
2199 detailedAction->setActionGroup(viewGroup);
2200 treeAction->setActionGroup(viewGroup);
2201 detailedTreeAction->setActionGroup(viewGroup);
2202
2203 KToggleAction *allowExpansionAction = new KToggleAction(i18n("Allow Expansion in Details View"), this);
2204 d->m_actions[AllowExpansionInDetailsView] = allowExpansionAction;
2205 connect(allowExpansionAction, &QAction::toggled, this, [this](bool allow) {
2206 d->slotToggleAllowExpansion(allow);
2207 });
2208
2209 KToggleAction *showHiddenAction = new KToggleAction(i18n("Show Hidden Files"), this);
2210 d->m_actions[ShowHiddenFiles] = showHiddenAction;
2211 showHiddenAction->setShortcuts(KStandardShortcut::showHideHiddenFiles());
2212 connect(showHiddenAction, &QAction::toggled, this, [this](bool show) {
2213 d->slotToggleHidden(show);
2214 });
2215
2216 KToggleAction *previewAction = new KToggleAction(i18n("Show Preview Panel"), this);
2217 d->m_actions[ShowPreviewPanel] = previewAction;
2218 previewAction->setShortcut(Qt::Key_F11);
2219 connect(previewAction, &QAction::toggled, this, [this](bool enable) {
2220 d->togglePreview(enable);
2221 });
2222
2223 KToggleAction *inlinePreview = new KToggleAction(QIcon::fromTheme(QStringLiteral("view-preview")), i18n("Show Preview"), this);
2224 d->m_actions[ShowPreview] = inlinePreview;
2225 inlinePreview->setShortcut(Qt::Key_F12);
2226 connect(inlinePreview, &QAction::toggled, this, [this](bool enable) {
2227 d->toggleInlinePreviews(enable);
2228 });
2229
2230 QAction *fileManager = new QAction(i18n("Open Containing Folder"), this);
2231 d->m_actions[OpenContainingFolder] = fileManager;
2232 fileManager->setIcon(QIcon::fromTheme(QStringLiteral("system-file-manager")));
2233 connect(fileManager, &QAction::triggered, this, [this]() {
2234 d->slotOpenFileManager();
2235 });
2236
2237 action = new QAction(i18n("Properties"), this);
2238 d->m_actions[Properties] = action;
2239 action->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")));
2240 action->setShortcut(Qt::ALT | Qt::Key_Return);
2241 connect(action, &QAction::triggered, this, [this]() {
2242 d->slotProperties();
2243 });
2244
2245 // the view menu actions
2246 KActionMenu *viewMenu = new KActionMenu(i18n("&View Mode"), this);
2247 d->m_actions[ViewModeMenu] = viewMenu;
2248 viewMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
2249 viewMenu->addAction(shortAction);
2250 viewMenu->addAction(detailedAction);
2251 // Comment following lines to hide the extra two modes
2252 viewMenu->addAction(treeAction);
2253 viewMenu->addAction(detailedTreeAction);
2254 // TODO: QAbstractItemView does not offer an action collection. Provide
2255 // an interface to add a custom action collection.
2256
2257 d->m_itemActions = new KFileItemActions(this);
2258
2259 d->m_newFileMenu = new KNewFileMenu(this);
2260 d->m_actions[KDirOperator::New] = d->m_newFileMenu;
2261 connect(d->m_newFileMenu, &KNewFileMenu::directoryCreated, this, [this](const QUrl &url) {
2262 d->slotDirectoryCreated(url);
2263 });
2264 connect(d->m_newFileMenu, &KNewFileMenu::selectExistingDir, this, [this](const QUrl &url) {
2265 setCurrentItem(url);
2266 });
2267
2268 const QList<QAction *> list = d->m_actions.values();
2269 for (QAction *action : list) {
2271 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
2272 }
2273}
2274
2276{
2277 setupMenu(SortActions | ViewActions | FileActions);
2278}
2279
2280void KDirOperator::setupMenu(int whichActions)
2281{
2282 // first fill the submenus (sort and view)
2283 KActionMenu *sortMenu = static_cast<KActionMenu *>(action(KDirOperator::SortMenu));
2284 sortMenu->menu()->clear();
2289 sortMenu->addSeparator();
2292 sortMenu->addSeparator();
2295
2296 // now plug everything into the popupmenu
2297 d->m_actionMenu->menu()->clear();
2298 if (whichActions & NavActions) {
2299 d->m_actionMenu->addAction(action(KDirOperator::Up));
2300 d->m_actionMenu->addAction(action(KDirOperator::Back));
2301 d->m_actionMenu->addAction(action(KDirOperator::Forward));
2302 d->m_actionMenu->addAction(action(KDirOperator::Home));
2303 d->m_actionMenu->addSeparator();
2304 }
2305
2306 if (whichActions & FileActions) {
2307 d->m_actionMenu->addAction(action(KDirOperator::New));
2308
2309 d->m_actionMenu->addAction(action(KDirOperator::Rename));
2310 action(KDirOperator::Rename)->setEnabled(KProtocolManager::supportsMoving(d->m_currUrl));
2311
2312 if (d->m_currUrl.isLocalFile() && !(QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
2313 d->m_actionMenu->addAction(action(KDirOperator::Trash));
2314 }
2315 KConfigGroup cg(KSharedConfig::openConfig(), QStringLiteral("KDE"));
2316 const bool del = !d->m_currUrl.isLocalFile() || (QApplication::keyboardModifiers() & Qt::ShiftModifier) || cg.readEntry("ShowDeleteCommand", false);
2317 if (del) {
2318 d->m_actionMenu->addAction(action(KDirOperator::Delete));
2319 }
2320 d->m_actionMenu->addSeparator();
2321 }
2322
2323 if (whichActions & SortActions) {
2324 d->m_actionMenu->addAction(sortMenu);
2325 if (!(whichActions & ViewActions)) {
2326 d->m_actionMenu->addSeparator();
2327 }
2328 }
2329
2330 if (whichActions & ViewActions) {
2331 d->m_actionMenu->addAction(action(KDirOperator::ViewModeMenu));
2332 d->m_actionMenu->addAction(action(KDirOperator::Reload));
2333 d->m_actionMenu->addSeparator();
2334 }
2335
2336 if (whichActions & FileActions) {
2337 d->m_actionMenu->addAction(action(KDirOperator::OpenContainingFolder));
2338 d->m_actionMenu->addAction(action(KDirOperator::Properties));
2339 }
2340}
2341
2343{
2346
2347 if (KFile::isSortByName(d->m_sorting)) {
2349 descending->setText(i18nc("Sort descending", "Z-A"));
2350 ascending->setText(i18nc("Sort ascending", "A-Z"));
2351 } else if (KFile::isSortByDate(d->m_sorting)) {
2353 descending->setText(i18nc("Sort descending", "Newest First"));
2354 ascending->setText(i18nc("Sort ascending", "Oldest First"));
2355 } else if (KFile::isSortBySize(d->m_sorting)) {
2357 descending->setText(i18nc("Sort descending", "Largest First"));
2358 ascending->setText(i18nc("Sort ascending", "Smallest First"));
2359 } else if (KFile::isSortByType(d->m_sorting)) {
2361 descending->setText(i18nc("Sort descending", "Z-A"));
2362 ascending->setText(i18nc("Sort ascending", "A-Z"));
2363 }
2364 ascending->setChecked(!(d->m_sorting & QDir::Reversed));
2365 descending->setChecked(d->m_sorting & QDir::Reversed);
2367}
2368
2370{
2371 KFile::FileView fv = static_cast<KFile::FileView>(d->m_viewKind);
2372
2373 // QAction *separateDirs = d->actionCollection->action("separate dirs");
2374 // separateDirs->setChecked(KFile::isSeparateDirs(fv) &&
2375 // separateDirs->isEnabled());
2376
2377 action(KDirOperator::ShortView)->setChecked(KFile::isSimpleView(fv));
2378 action(KDirOperator::DetailedView)->setChecked(KFile::isDetailView(fv));
2379 action(KDirOperator::TreeView)->setChecked(KFile::isTreeView(fv));
2380 action(KDirOperator::DetailedTreeView)->setChecked(KFile::isDetailTreeView(fv));
2381
2382 // dolphin style views
2383 action(KDirOperator::ViewIconsView)->setChecked(KFile::isSimpleView(fv) && d->m_decorationPosition == QStyleOptionViewItem::Top);
2384 action(KDirOperator::ViewCompactView)->setChecked(KFile::isSimpleView(fv) && d->m_decorationPosition == QStyleOptionViewItem::Left);
2385 action(KDirOperator::ViewDetailsView)->setChecked(KFile::isDetailTreeView(fv) || KFile::isDetailView(fv));
2386}
2387
2389{
2390 d->m_defaultView = 0;
2391 QString viewStyle = configGroup.readEntry("View Style", "DetailTree");
2392 if (viewStyle == QLatin1String("Detail")) {
2393 d->m_defaultView |= KFile::Detail;
2394 } else if (viewStyle == QLatin1String("Tree")) {
2395 d->m_defaultView |= KFile::Tree;
2396 } else if (viewStyle == QLatin1String("DetailTree")) {
2397 d->m_defaultView |= KFile::DetailTree;
2398 } else {
2399 d->m_defaultView |= KFile::Simple;
2400 }
2401 // if (configGroup.readEntry(QLatin1String("Separate Directories"),
2402 // DefaultMixDirsAndFiles)) {
2403 // d->defaultView |= KFile::SeparateDirs;
2404 //}
2405 if (configGroup.readEntry(QStringLiteral("Show Preview"), false)) {
2406 d->m_defaultView |= KFile::PreviewContents;
2407 }
2408
2409 d->m_previewWidth = configGroup.readEntry(QStringLiteral("Preview Width"), 100);
2410
2411 if (configGroup.readEntry(QStringLiteral("Show hidden files"), DefaultShowHidden)) {
2413 d->m_dirLister->setShowHiddenFiles(true);
2414 }
2415
2416 if (configGroup.readEntry(QStringLiteral("Allow Expansion"), DefaultShowHidden)) {
2417 action(KDirOperator::AllowExpansionInDetailsView)->setChecked(true);
2418 }
2419
2420 const bool hiddenFilesLast = configGroup.readEntry(QStringLiteral("Sort hidden files last"), DefaultHiddenFilesLast);
2422
2424 if (configGroup.readEntry(QStringLiteral("Sort directories first"), DefaultDirsFirst)) {
2426 }
2427 QString name = QStringLiteral("Name");
2428 QString sortBy = configGroup.readEntry(QStringLiteral("Sort by"), name);
2429 if (sortBy == name) {
2431 } else if (sortBy == QLatin1String("Size")) {
2433 } else if (sortBy == QLatin1String("Date")) {
2435 } else if (sortBy == QLatin1String("Type")) {
2437 }
2438 if (configGroup.readEntry(QStringLiteral("Sort reversed"), DefaultSortReversed)) {
2440 }
2441 d->updateSorting(sorting);
2442
2443 if (d->m_inlinePreviewState == KDirOperatorPrivate::NotForced) {
2444 d->m_showPreviews = configGroup.readEntry(QStringLiteral("Show Inline Previews"), true);
2445 }
2447 (QStyleOptionViewItem::Position)configGroup.readEntry(QStringLiteral("Decoration position"), (int)QStyleOptionViewItem::Top);
2449}
2450
2452{
2453 QString sortBy = QStringLiteral("Name");
2454 if (KFile::isSortBySize(d->m_sorting)) {
2455 sortBy = QStringLiteral("Size");
2456 } else if (KFile::isSortByDate(d->m_sorting)) {
2457 sortBy = QStringLiteral("Date");
2458 } else if (KFile::isSortByType(d->m_sorting)) {
2459 sortBy = QStringLiteral("Type");
2460 }
2461
2462 configGroup.writeEntry(QStringLiteral("Sort by"), sortBy);
2463
2464 configGroup.writeEntry(QStringLiteral("Sort reversed"), action(KDirOperator::SortDescending)->isChecked());
2465
2466 configGroup.writeEntry(QStringLiteral("Sort directories first"), action(KDirOperator::SortFoldersFirst)->isChecked());
2467
2468 const bool hiddenFilesLast = action(KDirOperator::SortHiddenFilesLast)->isChecked();
2469 configGroup.writeEntry(QStringLiteral("Sort hidden files last"), hiddenFilesLast);
2470
2471 // don't save the preview when an application specific preview is in use.
2472 bool appSpecificPreview = false;
2473 if (d->m_preview) {
2474 KFileMetaPreview *tmp = dynamic_cast<KFileMetaPreview *>(d->m_preview);
2475 appSpecificPreview = (tmp == nullptr);
2476 }
2477
2478 if (!appSpecificPreview) {
2479 KToggleAction *previewAction = static_cast<KToggleAction *>(action(KDirOperator::ShowPreviewPanel));
2480 if (previewAction->isEnabled()) {
2481 bool hasPreview = previewAction->isChecked();
2482 configGroup.writeEntry(QStringLiteral("Show Preview"), hasPreview);
2483
2484 if (hasPreview) {
2485 // remember the width of the preview widget
2486 QList<int> sizes = d->m_splitter->sizes();
2487 Q_ASSERT(sizes.count() == 2);
2488 configGroup.writeEntry(QStringLiteral("Preview Width"), sizes[1]);
2489 }
2490 }
2491 }
2492
2493 configGroup.writeEntry(QStringLiteral("Show hidden files"), action(KDirOperator::ShowHiddenFiles)->isChecked());
2494
2495 configGroup.writeEntry(QStringLiteral("Allow Expansion"), action(KDirOperator::AllowExpansionInDetailsView)->isChecked());
2496
2497 KFile::FileView fv = static_cast<KFile::FileView>(d->m_viewKind);
2498 QString style;
2499 if (KFile::isDetailView(fv)) {
2500 style = QStringLiteral("Detail");
2501 } else if (KFile::isSimpleView(fv)) {
2502 style = QStringLiteral("Simple");
2503 } else if (KFile::isTreeView(fv)) {
2504 style = QStringLiteral("Tree");
2505 } else if (KFile::isDetailTreeView(fv)) {
2506 style = QStringLiteral("DetailTree");
2507 }
2508 configGroup.writeEntry(QStringLiteral("View Style"), style);
2509
2510 if (d->m_inlinePreviewState == KDirOperatorPrivate::NotForced) {
2511 configGroup.writeEntry(QStringLiteral("Show Inline Previews"), d->m_showPreviews);
2512 d->writeIconZoomSettingsIfNeeded();
2513 }
2514
2515 configGroup.writeEntry(QStringLiteral("Decoration position"), (int)d->m_decorationPosition);
2516}
2517
2518void KDirOperatorPrivate::writeIconZoomSettingsIfNeeded()
2519{
2520 // must match behavior of iconSizeForViewType
2521 if (m_configGroup && m_itemView) {
2522 ZoomSettingsForView zoomSettings = zoomSettingsForView();
2523 if ((m_iconSize == zoomSettings.defaultValue) && !m_configGroup->hasDefault(zoomSettings.name)) {
2524 m_configGroup->revertToDefault(zoomSettings.name);
2525 } else {
2526 m_configGroup->writeEntry(zoomSettings.name, m_iconSize);
2527 }
2528 }
2529}
2530
2531void KDirOperator::resizeEvent(QResizeEvent *)
2532{
2533 // resize the m_splitter and assure that the width of
2534 // the preview widget is restored
2535 QList<int> sizes = d->m_splitter->sizes();
2536 const bool hasPreview = (sizes.count() == 2);
2537
2538 d->m_splitter->resize(size());
2539 sizes = d->m_splitter->sizes();
2540
2541 const bool restorePreviewWidth = hasPreview && (d->m_previewWidth != sizes[1]);
2542 if (restorePreviewWidth) {
2543 const int availableWidth = sizes[0] + sizes[1];
2544 sizes[0] = availableWidth - d->m_previewWidth;
2545 sizes[1] = d->m_previewWidth;
2546 d->m_splitter->setSizes(sizes);
2547 }
2548 if (hasPreview) {
2549 d->m_previewWidth = sizes[1];
2550 }
2551
2552 if (d->m_progressBar->parent() == this) {
2553 // Might be reparented into a statusbar
2554 const int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
2555 d->m_progressBar->move(frameWidth, height() - d->m_progressBar->height() - frameWidth);
2556 }
2557}
2558
2560{
2561 d->m_onlyDoubleClickSelectsFiles = enable;
2562 // TODO: port to QAbstractItemModel
2563 // if (d->itemView != 0) {
2564 // d->itemView->setOnlyDoubleClickSelectsFiles(enable);
2565 //}
2566}
2567
2569{
2570 return d->m_onlyDoubleClickSelectsFiles;
2571}
2572
2574{
2575 d->m_followNewDirectories = enable;
2576}
2577
2579{
2580 return d->m_followNewDirectories;
2581}
2582
2584{
2585 d->m_followSelectedDirectories = enable;
2586}
2587
2589{
2590 return d->m_followSelectedDirectories;
2591}
2592
2593void KDirOperatorPrivate::slotStarted()
2594{
2595 m_progressBar->setValue(0);
2596 // delay showing the progressbar for one second
2597 m_progressDelayTimer->setSingleShot(true);
2598 m_progressDelayTimer->start(1000);
2599}
2600
2601void KDirOperatorPrivate::slotShowProgress()
2602{
2603 m_progressBar->raise();
2604 m_progressBar->show();
2605}
2606
2607void KDirOperatorPrivate::slotProgress(int percent)
2608{
2609 m_progressBar->setValue(percent);
2610}
2611
2612void KDirOperatorPrivate::slotIOFinished()
2613{
2614 m_progressDelayTimer->stop();
2615 slotProgress(100);
2616 m_progressBar->hide();
2617 Q_EMIT q->finishedLoading();
2618 q->resetCursor();
2619
2620 if (m_preview) {
2621 m_preview->clearPreview();
2622 }
2623
2624 // m_lastUrl can be empty when e.g. kfilewidget is first opened
2625 if (!m_lastUrl.isEmpty() && m_dirHighlighting) {
2626 q->setCurrentItem(m_lastUrl);
2627 }
2628}
2629
2630void KDirOperatorPrivate::slotCanceled()
2631{
2632 Q_EMIT q->finishedLoading();
2633 q->resetCursor();
2634}
2635
2637{
2638 return d->m_progressBar;
2639}
2640
2642{
2643 qDeleteAll(d->m_backStack);
2644 d->m_backStack.clear();
2646
2647 qDeleteAll(d->m_forwardStack);
2648 d->m_forwardStack.clear();
2650}
2651
2653{
2654 d->m_dirHighlighting = enable;
2655}
2656
2658{
2659 return d->m_dirHighlighting;
2660}
2661
2663{
2664 return dirOnlyMode(d->m_mode);
2665}
2666
2667bool KDirOperator::dirOnlyMode(uint mode)
2668{
2669 return ((mode & KFile::Directory) && (mode & (KFile::File | KFile::Files)) == 0);
2670}
2671
2672void KDirOperatorPrivate::slotProperties()
2673{
2674 if (m_itemView == nullptr) {
2675 return;
2676 }
2677
2678 const KFileItemList list = q->selectedItems();
2679 if (!list.isEmpty()) {
2680 auto *dialog = new KPropertiesDialog(list, q);
2681 dialog->setAttribute(Qt::WA_DeleteOnClose);
2682 dialog->setModal(true);
2683 dialog->show();
2684 }
2685}
2686
2687void KDirOperatorPrivate::slotActivated(const QModelIndex &index)
2688{
2689 const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
2690 KFileItem item = m_dirModel->itemForIndex(dirIndex);
2691
2693 if (item.isNull() || (modifiers & Qt::ShiftModifier) || (modifiers & Qt::ControlModifier)) {
2694 return;
2695 }
2696
2697 if (item.isDir()) {
2698 // Only allow disabling following selected directories on Tree and
2699 // DetailTree views as selected directories in these views still expand
2700 // when selected. For other views, disabling following selected
2701 // directories would make selecting a directory a noop which is
2702 // unintuitive.
2703 if (m_followSelectedDirectories || (m_viewKind != KFile::Tree && m_viewKind != KFile::DetailTree)) {
2704 q->selectDir(item);
2705 }
2706 } else {
2707 q->selectFile(item);
2708 }
2709}
2710
2711void KDirOperatorPrivate::slotSelectionChanged()
2712{
2713 if (m_itemView == nullptr) {
2714 return;
2715 }
2716
2717 // In the multiselection mode each selection change is indicated by
2718 // emitting a null item. Also when the selection has been cleared, a
2719 // null item must be emitted.
2720 const bool multiSelectionMode = (m_itemView->selectionMode() == QAbstractItemView::ExtendedSelection);
2721 const bool hasSelection = m_itemView->selectionModel()->hasSelection();
2722 if (multiSelectionMode || !hasSelection) {
2723 KFileItem nullItem;
2724 q->highlightFile(nullItem);
2725 } else {
2726 const KFileItem selectedItem = q->selectedItems().constFirst();
2727 q->highlightFile(selectedItem);
2728 }
2729}
2730
2731void KDirOperatorPrivate::openContextMenu(const QPoint &pos)
2732{
2733 const QModelIndex proxyIndex = m_itemView->indexAt(pos);
2734 const QModelIndex dirIndex = m_proxyModel->mapToSource(proxyIndex);
2735 KFileItem item = m_dirModel->itemForIndex(dirIndex);
2736
2737 if (item.isNull()) {
2738 return;
2739 }
2740
2741 q->activatedMenu(item, QCursor::pos());
2742}
2743
2744void KDirOperatorPrivate::triggerPreview(const QModelIndex &index)
2745{
2746 if ((m_preview != nullptr && !m_preview->isHidden()) && index.isValid() && (index.column() == KDirModel::Name)) {
2747 const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
2748 const KFileItem item = m_dirModel->itemForIndex(dirIndex);
2749
2750 if (item.isNull()) {
2751 return;
2752 }
2753
2754 if (!item.isDir()) {
2755 m_previewUrl = item.url();
2756 showPreview();
2757 } else {
2758 m_preview->clearPreview();
2759 }
2760 }
2761}
2762
2763void KDirOperatorPrivate::showPreview()
2764{
2765 if (m_preview != nullptr) {
2766 m_preview->showPreview(m_previewUrl);
2767 }
2768}
2769
2770void KDirOperatorPrivate::slotSplitterMoved(int, int)
2771{
2772 const QList<int> sizes = m_splitter->sizes();
2773 if (sizes.count() == 2) {
2774 // remember the width of the preview widget (see KDirOperator::resizeEvent())
2775 m_previewWidth = sizes[1];
2776 }
2777}
2778
2779void KDirOperatorPrivate::assureVisibleSelection()
2780{
2781 if (m_itemView == nullptr) {
2782 return;
2783 }
2784
2785 QItemSelectionModel *selModel = m_itemView->selectionModel();
2786 if (selModel->hasSelection()) {
2787 const QModelIndex index = selModel->currentIndex();
2788 m_itemView->scrollTo(index, QAbstractItemView::EnsureVisible);
2789 triggerPreview(index);
2790 }
2791}
2792
2793void KDirOperatorPrivate::synchronizeSortingState(int logicalIndex, Qt::SortOrder order)
2794{
2795 QDir::SortFlags newSort = m_sorting & ~(QDirSortMask | QDir::Reversed);
2796
2797 switch (logicalIndex) {
2798 case KDirModel::Name:
2799 newSort |= QDir::Name;
2800 break;
2801 case KDirModel::Size:
2802 newSort |= QDir::Size;
2803 break;
2804 case KDirModel::ModifiedTime:
2805 newSort |= QDir::Time;
2806 break;
2807 case KDirModel::Type:
2808 newSort |= QDir::Type;
2809 break;
2810 default:
2811 Q_ASSERT(false);
2812 }
2813
2814 if (order == Qt::DescendingOrder) {
2815 newSort |= QDir::Reversed;
2816 }
2817
2818 updateSorting(newSort);
2819
2821 q,
2822 [this]() {
2823 assureVisibleSelection();
2824 },
2826}
2827
2828void KDirOperatorPrivate::slotChangeDecorationPosition()
2829{
2830 if (!m_itemView) {
2831 return;
2832 }
2833
2834 KDirOperatorIconView *view = qobject_cast<KDirOperatorIconView *>(m_itemView);
2835
2836 if (!view) {
2837 return;
2838 }
2839
2840 const bool leftChecked = q->action(KDirOperator::DecorationAtLeft)->isChecked();
2841
2842 if (leftChecked) {
2843 view->setDecorationPosition(QStyleOptionViewItem::Left);
2844 } else {
2845 view->setDecorationPosition(QStyleOptionViewItem::Top);
2846 }
2847
2848 m_itemView->update();
2849}
2850
2851void KDirOperatorPrivate::slotExpandToUrl(const QModelIndex &index)
2852{
2853 QTreeView *treeView = qobject_cast<QTreeView *>(m_itemView);
2854
2855 if (!treeView) {
2856 return;
2857 }
2858
2859 const KFileItem item = m_dirModel->itemForIndex(index);
2860
2861 if (item.isNull()) {
2862 return;
2863 }
2864
2865 if (!item.isDir()) {
2866 const QModelIndex proxyIndex = m_proxyModel->mapFromSource(index);
2867
2868 QList<QUrl>::Iterator it = m_itemsToBeSetAsCurrent.begin();
2869 while (it != m_itemsToBeSetAsCurrent.end()) {
2870 const QUrl url = *it;
2871 if (url.matches(item.url(), QUrl::StripTrailingSlash) || url.isParentOf(item.url())) {
2872 const KFileItem _item = m_dirLister->findByUrl(url);
2873 if (!_item.isNull() && _item.isDir()) {
2874 const QModelIndex _index = m_dirModel->indexForItem(_item);
2875 const QModelIndex _proxyIndex = m_proxyModel->mapFromSource(_index);
2876 treeView->expand(_proxyIndex);
2877
2878 // if we have expanded the last parent of this item, select it
2880 treeView->selectionModel()->select(proxyIndex, QItemSelectionModel::Select);
2881 }
2882 }
2883 it = m_itemsToBeSetAsCurrent.erase(it);
2884 } else {
2885 ++it;
2886 }
2887 }
2888 } else if (!m_itemsToBeSetAsCurrent.contains(item.url())) {
2889 m_itemsToBeSetAsCurrent << item.url();
2890 }
2891}
2892
2893void KDirOperatorPrivate::slotItemsChanged()
2894{
2895 m_completeListDirty = true;
2896}
2897
2898int KDirOperatorPrivate::iconSizeForViewType(QAbstractItemView *itemView) const
2899{
2900 // must match behavior of writeIconZoomSettingsIfNeeded
2901 if (!itemView || !m_configGroup) {
2902 return 0;
2903 }
2904
2905 ZoomSettingsForView zoomSettings = zoomSettingsForView();
2906 return m_configGroup->readEntry(zoomSettings.name, zoomSettings.defaultValue);
2907}
2908
2909KDirOperatorPrivate::ZoomSettingsForView KDirOperatorPrivate::zoomSettingsForView() const
2910{
2911 KFile::FileView fv = static_cast<KFile::FileView>(m_viewKind);
2912
2913 if (KFile::isSimpleView(fv)) {
2914 if (m_decorationPosition == QStyleOptionViewItem::Top) {
2915 // Simple view decoration above, aka Icons View
2916 return {QStringLiteral("iconViewIconSize"), static_cast<int>(KIconLoader::SizeHuge)};
2917 } else {
2918 // Simple view decoration left, aka compact view
2919 return {QStringLiteral("listViewIconSize"), static_cast<int>(KIconLoader::SizeHuge)};
2920 }
2921 }
2922
2923 const int smallIconSize = static_cast<int>(KIconLoader::SizeSmall);
2924 if (KFile::isTreeView(fv)) {
2925 return {QStringLiteral("treeViewIconSize"), smallIconSize};
2926 } else {
2927 // DetailView and DetailTreeView
2928 return {QStringLiteral("detailViewIconSize"), smallIconSize};
2929 }
2930}
2931
2933{
2934 delete d->m_configGroup;
2935 d->m_configGroup = new KConfigGroup(configGroup);
2936}
2937
2939{
2940 return d->m_configGroup;
2941}
2942
2947
2952
2954{
2955 return d->m_decorationPosition;
2956}
2957
2959{
2960 d->m_decorationPosition = position;
2961 const bool decorationAtLeft = d->m_decorationPosition == QStyleOptionViewItem::Left;
2962 action(KDirOperator::DecorationAtLeft)->setChecked(decorationAtLeft);
2963 action(KDirOperator::DecorationAtTop)->setChecked(!decorationAtLeft);
2964}
2965
2966bool KDirOperatorPrivate::isReadable(const QUrl &url)
2967{
2968 if (!url.isLocalFile()) {
2969 return true; // what else can we say?
2970 }
2971 const QFileInfo fileInfo(url.toLocalFile());
2972#ifdef Q_OS_WIN
2973 return fileInfo.isReadable() && fileInfo.isDir();
2974#else
2975 return fileInfo.isReadable();
2976#endif
2977}
2978
2979void KDirOperatorPrivate::slotDirectoryCreated(const QUrl &url)
2980{
2981 if (m_followNewDirectories) {
2982 q->setUrl(url, true);
2983 }
2984}
2985
2987{
2988 d->m_supportedSchemes = schemes;
2989 rereadDir();
2990}
2991
2993{
2994 return d->m_supportedSchemes;
2995}
2996
2997#include "moc_kdiroperator.cpp"
void setPopupMode(QToolButton::ToolButtonPopupMode popupMode)
void addAction(QAction *action)
virtual void clear()
void match(const QString &item)
void revertToDefault(const char *key, WriteConfigFlags pFlag=WriteConfigFlags())
bool hasDefault(const char *key) const
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
QString readEntry(const char *key, const char *aDefault=nullptr) const
void percent(int percent)
Progress signal showing the overall progress of the KCoreDirLister.
QFlags< OpenUrlFlag > OpenUrlFlags
Stores a combination of OpenUrlFlag values.
void clear()
Signals to the view to remove all items (when e.g. going from dirA to dirB).
void jobError(KIO::Job *job)
Emitted if listing a directory fails with an error.
void started(const QUrl &dirUrl)
Tell the view that this KCoreDirLister has started to list dirUrl.
void redirection(const QUrl &oldUrl, const QUrl &newUrl)
Signals a redirection.
void itemsDeleted(const KFileItemList &items)
Signal that items have been deleted.
@ Reload
Indicates whether to use the cache or to reread the directory from the disk.
@ NoFlags
No additional flags specified.
void canceled()
Tell the view that the user canceled the listing.
void newItems(const KFileItemList &items)
Signal new items.
void completed()
Tell the view that listing is finished.
Subclass of KCoreDirLister which uses QWidgets to show error messages and to associate jobs with wind...
Definition kdirlister.h:25
A model for a KIO-based directory tree.
Definition kdirmodel.h:42
void expand(const QModelIndex &index)
Emitted for each subdirectory that is a parent of a url passed to expandToUrl This allows to asynchro...
@ DropOnDirectory
allow drops on any directory
Definition kdirmodel.h:170
@ FileItemRole
returns the KFileItem for a given index. roleName is "fileItem".
Definition kdirmodel.h:160
This widget works as a network transparent filebrowser.
void setNewFileMenuSupportedMimeTypes(const QStringList &mime)
Only show the files in a given set of MIME types.
void setIconSize(int value)
Notifies that the icons size should change.
void keyEnterReturnPressed()
Triggered when the user hit Enter/Return.
virtual void setDropOptions(int options)
Sets the options for dropping files.
virtual void setAcceptDrops(bool b)
Reimplemented - allow dropping of files if b is true, defaults to true since 5.59.
QDir::SortFlags sorting() const
KFile::Modes mode() const
void setInlinePreviewShown(bool show)
Forces the inline previews to be shown or hidden, depending on show.
void setSupportedSchemes(const QStringList &schemes)
Set the URL schemes that the file widget should allow navigating to.
virtual void selectDir(const KFileItem &item)
Enters the directory specified by the given item.
QProgressBar * progressBar() const
void renamingFinished(const QList< QUrl > &urls)
Emitted when renaming selected files has finished.
QStringList mimeFilter() const
KFileItemList selectedItems() const
void sortByDate()
Changes sorting to sort by date.
bool followNewDirectories() const
KDirOperator(const QUrl &urlName=QUrl{}, QWidget *parent=nullptr)
Constructs the KDirOperator with no initial view.
QStringList supportedSchemes() const
Returns the URL schemes that the file widget should allow navigating to.
KCompletion * dirCompletionObject() const
QString nameFilter() const
virtual void setShowHiddenFiles(bool s)
Enables/disables showing hidden files.
void setMimeFilter(const QStringList &mimetypes)
Sets a list of MIME types as filter.
int numFiles() const
void sortReversed()
Changes sorting to reverse sorting.
void showOpenWithActions(bool enable)
Call with true to add open-with actions to items in the view.
virtual void rereadDir()
Re-reads the current url.
void setupActions()
Sets up all the actions.
virtual void setMode(KFile::Modes m)
Sets the listing/selection mode for the views, an OR'ed combination of.
void setFollowNewDirectories(bool enable)
Toggles whether setUrl is called on newly created directories.
void updateSortActions()
Updates the sorting-related actions to comply with the current sorting.
KDirLister * dirLister() const
QString makeCompletion(const QString &)
Tries to complete the given string (only completes files).
void updateSelectionDependentActions()
Enables/disables actions that are selection dependent.
KFilePreviewGenerator * previewGenerator() const
Returns the preview generator for the current view.
void close()
Stops loading immediately.
bool isInlinePreviewShown() const
Returns whether the inline previews are shown or not.
KCompletion * completionObject() const
void toggleIgnoreCase()
Toggles case sensitive / case insensitive sorting.
void prepareCompletionObjects()
Synchronizes the completion objects with the entries of the currently listed url.
virtual void readConfig(const KConfigGroup &configGroup)
Reads the default settings for a view, i.e. the default KFile::FileView.
void updateViewActions()
Updates the view-related actions to comply with the current KFile::FileView.
virtual void forward()
Goes one step forward in the history and opens that url.
void setCurrentItem(const QUrl &url)
Clears the current selection and attempts to set url the current url file.
void setSorting(QDir::SortFlags)
Sets the way to sort files and directories.
void setNameFilter(const QString &filter)
Sets a filter like "*.cpp *.h *.o".
virtual void back()
Goes one step back in the history and opens that url.
virtual QAbstractItemView * createView(QWidget *parent, KFile::FileView viewKind)
A view factory for creating predefined fileviews.
QAbstractItemView * view() const
bool isSelected(const KFileItem &item) const
QUrl url() const
void toggleDirsFirst()
Toggles showing directories first / having them sorted like files.
void fileHighlighted(const KFileItem &item, bool isKeyNavigation)
Emitted when a file is highlighted or generally the selection changes in multiselection mode.
int iconSize() const
Returns the icon size in pixels, ranged from KIconLoader::SizeSmall (16) to KIconLoader::SizeEnormous...
virtual void setUrl(const QUrl &url, bool clearforward)
Sets a new url to list.
virtual void writeConfig(KConfigGroup &configGroup)
Saves the current settings like sorting, simple or detailed view.
void clearHistory()
Clears the forward and backward history.
void contextMenuAboutToShow(const KFileItem &item, QMenu *menu)
Emitted just before the context menu is shown, allows users to extend the menu with custom actions.
Action
Actions provided by KDirOperator that can be accessed from the outside using action()
@ SortByDate
Sorts by date.
@ SortAscending
Changes sort order to ascending.
@ Up
Changes to the parent directory.
@ SortFoldersFirst
Sorts folders before files.
@ ViewModeMenu
an ActionMenu containing all actions concerning the view
@ Home
Changes to the user's home directory.
@ SortByType
Sorts by type.
@ SortDescending
Changes sort order to descending.
@ SortBySize
Sorts by size.
@ PopupMenu
An ActionMenu presenting a popupmenu with all actions.
@ ShowHiddenFiles
shows hidden files
@ ShowPreviewPanel
shows a preview next to the fileview
@ Properties
Shows a KPropertiesDialog for the selected files.
@ DetailedView
Shows a detailed fileview (dates, permissions ,...)
@ Forward
Goes forward in the history.
@ NewFolder
Opens a dialog box to create a directory.
@ Delete
Deletes the selected files/directories.
@ ShortView
Shows a simple fileview.
@ SortMenu
An ActionMenu containing all sort-options.
@ SortHiddenFilesLast
Sorts hidden files last.
@ Reload
Reloads the current directory.
@ Back
Goes back to the previous directory.
@ SortByName
Sorts by name.
virtual void trashSelected()
Trashes the currently selected files/directories.
void setFollowSelectedDirectories(bool enable)
Toggles whether setUrl is called on selected directories when a tree view is used.
bool followSelectedDirectories() const
void sortByName()
Changes sorting to sort by name.
virtual void cdUp()
Goes one directory up from the current url.
bool onlyDoubleClickSelectsFiles() const
void clearFilter()
Clears both the namefilter and MIME type filter, so that all files and directories will be shown.
void highlightFile(const KFileItem &item)
Emits fileHighlighted(item)
void setViewMode(KFile::FileView viewKind)
Set the view mode to one of the predefined modes.
void slotCompletionMatch(const QString &match)
Tries to make the given match as current item in the view and emits completion( match )
virtual KIO::DeleteJob * del(const KFileItemList &items, QWidget *parent=nullptr, bool ask=true, bool showProgress=true)
Starts and returns a KIO::DeleteJob to delete the given items.
QStringList newFileMenuSupportedMimeTypes() const
virtual void setDirLister(KDirLister *lister)
Sets a custom KDirLister to list directories.
QString makeDirCompletion(const QString &)
Tries to complete the given string (only completes directories).
bool showHiddenFiles() const
void sortByType()
Changes sorting to sort by date.
void updateDir()
to update the view after changing the settings
void resetCursor()
Restores the normal cursor after showing the busy-cursor.
virtual void mkdir()
Opens a dialog to create a new directory.
bool isSaving() const
Returns whether KDirOperator will force a double click to accept.
bool isRoot() const
void selectFile(const KFileItem &item)
Emits fileSelected( item )
virtual void deleteSelected()
Deletes the currently selected files/directories.
void setIsSaving(bool isSaving)
If the system is set up to trigger items on single click, if isSaving is true, we will force to doubl...
void setOnlyDoubleClickSelectsFiles(bool enable)
This toggles between double/single click file and directory selection mode.
bool dirHighlighting() const
virtual void activatedMenu(const KFileItem &item, const QPoint &pos)
Called upon right-click to activate the popupmenu.
QList< QAction * > allActions() const
A list of all actions for this KDirOperator.
void setNewFileMenuSelectDirWhenAlreadyExist(bool selectOnDirExists)
Setting this to true will make a directory get selected when trying to create a new one that has the ...
void viewChanged(QAbstractItemView *newView)
Emitted whenever the current fileview is changed, either by an explicit call to setView() or by the u...
QAction * action(KDirOperator::Action action) const
Obtain a given action from the KDirOperator's set of actions.
void setupMenu()
Sets up the context-menu with all the necessary actions.
virtual void setPreviewWidget(KPreviewWidgetBase *w)
Sets a preview-widget to be shown next to the file-view.
void currentIconSizeChanged(int size)
Will notify that the icon size has changed.
bool dirOnlyMode() const
virtual void home()
Enters the home directory.
void renameSelected()
Initiates a rename operation on the currently selected files/directories, prompting the user to choos...
~KDirOperator() override
Destroys the KDirOperator.
void setDecorationPosition(QStyleOptionViewItem::Position position)
Sets the position where icons shall be shown relative to the labels of file items in the icon view.
void pathChanged()
Called after setUrl() to load the directory, update the history, etc.
virtual KIO::CopyJob * trash(const KFileItemList &items, QWidget *parent, bool ask=true, bool showProgress=true)
Starts and returns a KIO::CopyJob to trash the given items.
KConfigGroup * viewConfigGroup() const
QStyleOptionViewItem::Position decorationPosition() const
Returns the position where icons are shown relative to the labels of file items in the icon view.
KFile::FileView viewMode() const
Returns the current view mode.
virtual void setEnableDirHighlighting(bool enable)
When using the up or back actions to navigate the directory hierarchy, KDirOperator can highlight the...
void sortBySize()
Changes sorting to sort by size.
int numDirs() const
void setCurrentItems(const QList< QUrl > &urls)
Clears the current selection and attempts to set urls the current url files.
virtual void setViewConfig(KConfigGroup &configGroup)
Sets the config object and the to be used group in KDirOperator.
bool checkPreviewSupport()
Checks if there support from KIO::PreviewJob for the currently shown files, taking mimeFilter() and n...
Acts as proxy model for KDirModel to sort and filter KFileItems.
This class creates and handles the actions for a url (or urls) in a popupmenu.
List of KFileItems, which adds a few helper methods to QList<KFileItem>.
Definition kfileitem.h:632
QList< QUrl > urlList() const
A KFileItem is a generic class to handle a file, local or remote.
Definition kfileitem.h:36
bool isNull() const
Return true if default-constructed.
Generates previews for files of an item view.
KFile is a class which provides a namespace for some enumerated values associated with the kfile libr...
Definition kfile.h:24
QFlags< Mode > Modes
Stores a combination of Mode values.
Definition kfile.h:47
The AskUserActionInterface class allows a KIO::Job to prompt the user for a decision when e....
CopyJob is used to move, copy or symlink files and directories.
Definition copyjob.h:41
A more complex Job to delete files and directories.
Definition deletejob.h:34
This job asks the user for confirmation to delete or move to Trash a list of URLs; or if the job is c...
A UI delegate tuned to be used with KIO Jobs.
bool askDeleteConfirmation(const QList< QUrl > &urls, DeletionType deletionType, ConfirmationType confirmationType) override
Ask for confirmation before deleting/trashing urls.
void setWindow(QWidget *window) override
Associate this job with a window given by window.
static QStringList supportedMimeTypes()
Returns a list of all supported MIME types.
Dialog for renaming a variable number of files.
A KIO job that retrieves information about a file or directory.
Definition statjob.h:26
const UDSEntry & statResult() const
Result of the stat operation.
Definition statjob.cpp:80
Universal Directory Service.
Definition udsentry.h:79
bool isDir() const
Definition udsentry.cpp:375
void setAutoErrorHandlingEnabled(bool enable)
bool exec()
KJobUiDelegate * uiDelegate() const
The 'Create New' submenu, for creating files using templates (e.g. "new HTML file") and directories.
void directoryCreated(const QUrl &url)
Emitted once the directory url has been successfully created.
void selectExistingDir(const QUrl &url)
Emitted when trying to create a new directory that has the same name as an existing one,...
Abstract baseclass for all preview widgets which shall be used via KFileDialog::setPreviewWidget(cons...
static bool supportsListing(const QUrl &url)
Returns whether the protocol can list files/objects.
static bool supportsMoving(const QUrl &url)
Returns whether the protocol can move files/objects between different locations.
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KIOCORE_EXPORT DeleteJob * del(const QUrl &src, JobFlags flags=DefaultFlags)
Delete a file or directory.
OpenFileManagerWindowJob * highlightInFileManager(const QList< QUrl > &urls, const QByteArray &asn)
Convenience method for creating a job to highlight a certain file or folder.
KIOCORE_EXPORT StatJob * stat(const QUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
Definition statjob.cpp:203
KIOCORE_EXPORT ListJob * listDir(const QUrl &url, JobFlags flags=DefaultFlags, ListJob::ListFlags listFlags=ListJob::ListFlag::IncludeHidden)
List the contents of url, which is assumed to be a directory.
Definition listjob.cpp:239
KIOCORE_EXPORT CopyJob * trash(const QUrl &src, JobFlags flags=DefaultFlags)
Trash a file or directory.
Definition copyjob.cpp:2710
QFlags< JobFlag > JobFlags
Stores a combination of JobFlag values.
Definition job_base.h:281
@ DefaultFlags
Show the progress info GUI, no Resume and no Overwrite.
Definition job_base.h:246
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
Definition job_base.h:251
QString name(const QVariant &location)
void setWindow(QObject *job, QWidget *widget)
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
QAction * zoom(const QObject *recvr, const char *slot, QObject *parent)
QAction * create(StandardAction id, const Receiver *recvr, Func slot, QObject *parent, std::optional< Qt::ConnectionType > connectionType=std::nullopt)
const QList< QKeySequence > & showHideHiddenFiles()
const QList< QKeySequence > & shortcut(StandardShortcut id)
const QList< QKeySequence > & openContextMenu()
KCOREADDONS_EXPORT QList< QUrl > urlsFromMimeData(const QMimeData *mimeData, DecodeOptions decodeOptions=PreferKdeUrls, MetaDataMap *metaData=nullptr)
void activated(const QModelIndex &index)
void entered(const QModelIndex &index)
QItemSelectionModel * selectionModel() const const
void setChecked(bool)
void setEnabled(bool)
void setIcon(const QIcon &icon)
QMenu * menu() const const
void setActionGroup(QActionGroup *group)
void setShortcuts(QKeySequence::StandardKey key)
QList< QKeySequence > shortcuts() const const
void setText(const QString &text)
void toggled(bool checked)
void setToolTip(const QString &tip)
void triggered(bool checked)
void setExclusive(bool b)
QPoint pos()
virtual void open()
QString currentPath()
QString homePath()
const QMimeData * mimeData() const const
void accept()
Qt::KeyboardModifiers keyboardModifiers()
void restoreOverrideCursor()
void setOverrideCursor(const QCursor &cursor)
void setSortIndicator(int logicalIndex, Qt::SortOrder order)
void sortIndicatorChanged(int logicalIndex, Qt::SortOrder order)
QIcon fromTheme(const QString &name)
Qt::KeyboardModifiers modifiers() const const
QModelIndexList indexes() const const
virtual void clear()
void currentChanged(const QModelIndex &current, const QModelIndex &previous)
QModelIndex currentIndex() const const
bool hasSelection() const const
virtual void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
virtual void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
int key() const const
typedef Iterator
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
iterator begin()
void clear()
const T & constFirst() const const
qsizetype count() const const
iterator end()
iterator erase(const_iterator begin, const_iterator end)
bool isEmpty() const const
qsizetype size() const const
void clear()
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
QMimeType mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const const
QMimeType mimeTypeForUrl(const QUrl &url) const const
bool isValid() const const
int column() const const
bool isValid() const const
Q_EMITQ_EMIT
bool blockSignals(bool block)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
virtual bool event(QEvent *e)
virtual bool eventFilter(QObject *watched, QEvent *event)
void installEventFilter(QObject *filterObj)
QObject * parent() const const
T qobject_cast(QObject *object)
void removeEventFilter(QObject *obj)
int & ry()
int y() const const
void setValue(int value)
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
void setPattern(const QString &pattern)
QString wildcardToRegularExpression(QStringView pattern, WildcardConversionOptions options)
bool hasMatch() const const
Qt::GestureType grabGesture(QObject *target, ScrollerGestureType scrollGestureType)
QScroller * scroller(QObject *target)
void setScrollerProperties(const QScrollerProperties &prop)
void stateChanged(QScroller::State newState)
void setScrollMetric(ScrollMetric metric, const QVariant &value)
Qt::MouseButton button() const const
void splitterMoved(int pos, int index)
QString & append(QChar ch)
qsizetype length() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
PM_DefaultFrameWidth
SH_ItemView_ActivateItemOnSingleClick
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
CaseSensitivity
QueuedConnection
CustomContextMenu
WaitCursor
WheelFocus
TapGesture
Key_Return
ShiftModifier
LeftToRight
BackButton
WidgetWithChildrenShortcut
SortOrder
SkipEmptyParts
WA_AcceptTouchEvents
void setSingleShot(bool singleShot)
void start()
void timeout()
void expand(const QModelIndex &index)
QHeaderView * header() const const
StripTrailingSlash
QUrl adjusted(FormattingOptions options) const const
QUrl fromLocalFile(const QString &localFile)
bool isEmpty() const const
bool isLocalFile() const const
bool isParentOf(const QUrl &childUrl) const const
bool isValid() const const
bool matches(const QUrl &url, FormattingOptions options) const const
QString path(ComponentFormattingOptions options) const const
QUrl resolved(const QUrl &relative) const const
QString scheme() const const
QString toLocalFile() const const
QPoint angleDelta() const const
QWidget * topLevelWidget() const const
QWidget(QWidget *parent, Qt::WindowFlags f)
void setAcceptDrops(bool on)
QAction * addAction(const QIcon &icon, const QString &text)
virtual void changeEvent(QEvent *event)
void customContextMenuRequested(const QPoint &pos)
virtual bool event(QEvent *event) override
void setFocusPolicy(Qt::FocusPolicy policy)
void setLayoutDirection(Qt::LayoutDirection direction)
void setFocus()
void setFocusProxy(QWidget *w)
void show()
QStyle * style() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 11 2025 11:51:43 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.