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

KDE's Doxygen guidelines are available online.