fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kfile / kdiroperator.cpp
blobadb6a4d7b45621251ab8d75e5ab4bd47d1946aab
1 /* This file is part of the KDE libraries
2 Copyright (C) 1999,2000 Stephan Kulow <coolo@kde.org>
3 1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include "kdiroperator.h"
22 #include "kdirmodel.h"
23 #include "kdiroperatordetailview_p.h"
24 #include "kdirsortfilterproxymodel.h"
25 #include "kfileitem.h"
26 #include "kfilemetapreview.h"
27 #include "kpreviewwidgetbase.h"
29 #include <config-kfile.h>
31 #include <unistd.h>
33 #include <QtCore/QDir>
34 #include <QtCore/QRegExp>
35 #include <QtCore/QTimer>
36 #include <QtCore/QAbstractItemModel>
37 #include <QtGui/QApplication>
38 #include <QtGui/QDialog>
39 #include <QtGui/QHeaderView>
40 #include <QtGui/QLabel>
41 #include <QtGui/QLayout>
42 #include <QtGui/QListView>
43 #include <QtGui/QMouseEvent>
44 #include <QtGui/QTreeView>
45 #include <QtGui/QPushButton>
46 #include <QtGui/QProgressBar>
47 #include <QtGui/QScrollBar>
48 #include <QtGui/QSplitter>
49 #include <QtGui/QWheelEvent>
51 #include <kaction.h>
52 #include <kapplication.h>
53 #include <kdebug.h>
54 #include <kdialog.h>
55 #include <kdirlister.h>
56 #include <kfileitemdelegate.h>
57 #include <kicon.h>
58 #include <kinputdialog.h>
59 #include <klocale.h>
60 #include <kmessagebox.h>
61 #include <kmenu.h>
62 #include <kstandardaction.h>
63 #include <kio/job.h>
64 #include <kio/deletejob.h>
65 #include <kio/copyjob.h>
66 #include <kio/jobuidelegate.h>
67 #include <kio/jobclasses.h>
68 #include <kio/netaccess.h>
69 #include <kio/previewjob.h>
70 #include <kio/renamedialog.h>
71 #include <kfilepreviewgenerator.h>
72 #include <kpropertiesdialog.h>
73 #include <kstandardshortcut.h>
74 #include <kde_file.h>
75 #include <kactioncollection.h>
76 #include <ktoggleaction.h>
77 #include <kactionmenu.h>
78 #include <kconfiggroup.h>
79 #include <kdeversion.h>
82 template class QHash<QString, KFileItem>;
84 static QStyleOptionViewItem::Position decorationPosition = QStyleOptionViewItem::Left;
86 /**
87 * Default icon view for KDirOperator using
88 * custom view options.
90 class KDirOperatorIconView : public QListView
92 public:
93 KDirOperatorIconView(QWidget *parent = 0);
94 virtual ~KDirOperatorIconView();
96 protected:
97 virtual QStyleOptionViewItem viewOptions() const;
98 virtual void dragEnterEvent(QDragEnterEvent* event);
99 virtual void mousePressEvent(QMouseEvent *event);
100 virtual void wheelEvent(QWheelEvent *event);
103 KDirOperatorIconView::KDirOperatorIconView(QWidget *parent) :
104 QListView(parent)
106 setViewMode(QListView::IconMode);
107 setFlow(QListView::TopToBottom);
108 setResizeMode(QListView::Adjust);
109 setSpacing(KDialog::spacingHint());
110 setMovement(QListView::Static);
111 setDragDropMode(QListView::DragOnly);
112 setVerticalScrollMode(QListView::ScrollPerPixel);
113 setHorizontalScrollMode(QListView::ScrollPerPixel);
114 setEditTriggers(QAbstractItemView::NoEditTriggers);
115 setWordWrap(true);
116 setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall));
119 KDirOperatorIconView::~KDirOperatorIconView()
123 QStyleOptionViewItem KDirOperatorIconView::viewOptions() const
125 QStyleOptionViewItem viewOptions = QListView::viewOptions();
126 viewOptions.showDecorationSelected = true;
127 viewOptions.decorationPosition = decorationPosition;
128 if (decorationPosition == QStyleOptionViewItem::Left) {
129 viewOptions.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
130 } else {
131 viewOptions.displayAlignment = Qt::AlignCenter;
134 return viewOptions;
137 void KDirOperatorIconView::dragEnterEvent(QDragEnterEvent* event)
139 if (event->mimeData()->hasUrls()) {
140 event->acceptProposedAction();
144 void KDirOperatorIconView::mousePressEvent(QMouseEvent *event)
146 if (!indexAt(event->pos()).isValid()) {
147 const Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
148 if (!(modifiers & Qt::ShiftModifier) && !(modifiers & Qt::ControlModifier)) {
149 clearSelection();
153 QListView::mousePressEvent(event);
156 void KDirOperatorIconView::wheelEvent(QWheelEvent *event)
158 QListView::wheelEvent(event);
160 // apply the vertical wheel event to the horizontal scrollbar, as
161 // the items are aligned from left to right
162 if (event->orientation() == Qt::Vertical) {
163 QWheelEvent horizEvent(event->pos(),
164 event->delta(),
165 event->buttons(),
166 event->modifiers(),
167 Qt::Horizontal);
168 QApplication::sendEvent(horizontalScrollBar(), &horizEvent);
172 class KDirOperator::Private
174 public:
175 Private( KDirOperator *parent );
176 ~Private();
178 enum InlinePreviewState {
179 ForcedToFalse = 0,
180 ForcedToTrue,
181 NotForced
184 // private methods
185 bool checkPreviewInternal() const;
186 void checkPath(const QString &txt, bool takeFiles = false);
187 bool openUrl(const KUrl &url, KDirLister::OpenUrlFlags flags = KDirLister::NoFlags);
188 int sortColumn() const;
189 Qt::SortOrder sortOrder() const;
190 void triggerSorting();
192 static bool isReadable(const KUrl &url);
194 KFile::FileView allViews();
196 // private slots
197 void _k_slotDetailedView();
198 void _k_slotSimpleView();
199 void _k_slotTreeView();
200 void _k_slotDetailedTreeView();
201 void _k_slotToggleHidden(bool);
202 void _k_togglePreview(bool);
203 void _k_toggleInlinePreviews(bool);
204 void _k_slotSortByName();
205 void _k_slotSortBySize();
206 void _k_slotSortByDate();
207 void _k_slotSortByType();
208 void _k_slotSortReversed(bool doReverse);
209 void _k_slotToggleDirsFirst();
210 void _k_slotToggleIgnoreCase();
211 void _k_slotStarted();
212 void _k_slotProgress(int);
213 void _k_slotShowProgress();
214 void _k_slotIOFinished();
215 void _k_slotCanceled();
216 void _k_slotRedirected(const KUrl&);
217 void _k_slotProperties();
218 void _k_slotPressed(const QModelIndex&);
219 void _k_slotActivated(const QModelIndex&);
220 void _k_slotDoubleClicked(const QModelIndex&);
221 void _k_slotSelectionChanged();
222 void _k_openContextMenu(const QPoint&);
223 void _k_triggerPreview(const QModelIndex&);
224 void _k_showPreview();
225 void _k_slotSplitterMoved(int, int);
226 void _k_assureVisibleSelection();
227 void _k_synchronizeSortingState(int, Qt::SortOrder);
228 void _k_slotChangeDecorationPosition();
229 void _k_slotExpandToUrl(const QModelIndex&);
231 void updateListViewGrid();
232 int iconSizeForViewType(QAbstractItemView *itemView) const;
234 // private members
235 KDirOperator *parent;
236 QStack<KUrl*> backStack; ///< Contains all URLs you can reach with the back button.
237 QStack<KUrl*> forwardStack; ///< Contains all URLs you can reach with the forward button.
239 QModelIndex lastHoveredIndex;
241 KDirLister *dirLister;
242 KUrl currUrl;
244 KCompletion completion;
245 KCompletion dirCompletion;
246 bool completeListDirty;
247 QDir::SortFlags sorting;
249 QSplitter *splitter;
251 QAbstractItemView *itemView;
252 KDirModel *dirModel;
253 KDirSortFilterProxyModel *proxyModel;
255 KFileItemList pendingMimeTypes;
257 // the enum KFile::FileView as an int
258 int viewKind;
259 int defaultView;
261 KFile::Modes mode;
262 QProgressBar *progressBar;
264 KPreviewWidgetBase *preview;
265 KUrl previewUrl;
266 int previewWidth;
268 bool leftButtonPressed;
269 bool dirHighlighting;
270 bool onlyDoubleClickSelectsFiles;
271 QString lastURL; // used for highlighting a directory on cdUp
272 QTimer *progressDelayTimer;
273 int dropOptions;
275 KActionMenu *actionMenu;
276 KActionCollection *actionCollection;
278 KConfigGroup *configGroup;
280 KFilePreviewGenerator *previewGenerator;
282 bool showPreviews;
283 int iconsZoom;
285 bool isSaving;
287 KActionMenu *decorationMenu;
288 KToggleAction *leftAction;
289 KUrl::List itemsToBeSetAsCurrent;
290 bool shouldFetchForItems;
291 InlinePreviewState inlinePreviewState;
294 KDirOperator::Private::Private(KDirOperator *_parent) :
295 parent(_parent),
296 dirLister(0),
297 splitter(0),
298 itemView(0),
299 dirModel(0),
300 proxyModel(0),
301 progressBar(0),
302 preview(0),
303 previewUrl(),
304 previewWidth(0),
305 leftButtonPressed(false),
306 dirHighlighting(false),
307 onlyDoubleClickSelectsFiles(!KGlobalSettings::singleClick()),
308 progressDelayTimer(0),
309 dropOptions(0),
310 actionMenu(0),
311 actionCollection(0),
312 configGroup(0),
313 previewGenerator(0),
314 showPreviews(false),
315 iconsZoom(0),
316 isSaving(false),
317 decorationMenu(0),
318 leftAction(0),
319 shouldFetchForItems(false),
320 inlinePreviewState(NotForced)
324 KDirOperator::Private::~Private()
326 delete itemView;
327 itemView = 0;
329 // TODO:
330 // if (configGroup) {
331 // itemView->writeConfig(configGroup);
332 // }
334 qDeleteAll(backStack);
335 qDeleteAll(forwardStack);
336 delete preview;
337 preview = 0;
339 delete proxyModel;
340 proxyModel = 0;
341 delete dirModel;
342 dirModel = 0;
343 dirLister = 0; // deleted by KDirModel
344 delete configGroup;
345 configGroup = 0;
347 delete progressDelayTimer;
348 progressDelayTimer = 0;
351 KDirOperator::KDirOperator(const KUrl& _url, QWidget *parent) :
352 QWidget(parent),
353 d(new Private(this))
355 d->splitter = new QSplitter(this);
356 d->splitter->setChildrenCollapsible(false);
357 connect(d->splitter, SIGNAL(splitterMoved(int, int)),
358 this, SLOT(_k_slotSplitterMoved(int, int)));
360 d->preview = 0;
362 d->mode = KFile::File;
363 d->viewKind = KFile::Simple;
364 d->sorting = QDir::Name | QDir::DirsFirst;
366 if (_url.isEmpty()) { // no dir specified -> current dir
367 QString strPath = QDir::currentPath();
368 strPath.append(QChar('/'));
369 d->currUrl = KUrl();
370 d->currUrl.setProtocol(QLatin1String("file"));
371 d->currUrl.setPath(strPath);
372 } else {
373 d->currUrl = _url;
374 if (d->currUrl.protocol().isEmpty())
375 d->currUrl.setProtocol(QLatin1String("file"));
377 d->currUrl.addPath("/"); // make sure we have a trailing slash!
380 // We set the direction of this widget to LTR, since even on RTL desktops
381 // viewing directory listings in RTL mode makes people's head explode.
382 // Is this the correct place? Maybe it should be in some lower level widgets...?
383 setLayoutDirection(Qt::LeftToRight);
384 setDirLister(new KDirLister());
386 connect(&d->completion, SIGNAL(match(const QString&)),
387 SLOT(slotCompletionMatch(const QString&)));
389 d->progressBar = new QProgressBar(this);
390 d->progressBar->setObjectName("d->progressBar");
391 d->progressBar->adjustSize();
392 d->progressBar->move(2, height() - d->progressBar->height() - 2);
394 d->progressDelayTimer = new QTimer(this);
395 d->progressDelayTimer->setObjectName(QLatin1String("d->progressBar delay timer"));
396 connect(d->progressDelayTimer, SIGNAL(timeout()),
397 SLOT(_k_slotShowProgress()));
399 d->completeListDirty = false;
401 // action stuff
402 setupActions();
403 setupMenu();
405 setFocusPolicy(Qt::WheelFocus);
408 KDirOperator::~KDirOperator()
410 resetCursor();
411 delete d;
415 void KDirOperator::setSorting(QDir::SortFlags spec)
417 d->sorting = spec;
418 d->triggerSorting();
419 updateSortActions();
422 QDir::SortFlags KDirOperator::sorting() const
424 return d->sorting;
427 bool KDirOperator::isRoot() const
429 #ifdef Q_WS_WIN
430 if (url().isLocalFile()) {
431 const QString path = url().toLocalFile();
432 if (path.length() >= 2)
433 return (path[0].isLetter() && path[1] == ':');
434 return false;
435 } else
436 #endif
437 return url().path() == QString(QLatin1Char('/'));
440 KDirLister *KDirOperator::dirLister() const
442 return d->dirLister;
445 void KDirOperator::resetCursor()
447 if (qApp)
448 QApplication::restoreOverrideCursor();
449 d->progressBar->hide();
452 void KDirOperator::sortByName()
454 d->sorting = QDir::Name;
455 d->actionCollection->action("by name")->setChecked(true);
458 void KDirOperator::sortBySize()
460 d->sorting = (d->sorting & ~QDir::SortByMask) | QDir::Size;
461 d->actionCollection->action("by size")->setChecked(true);
464 void KDirOperator::sortByDate()
466 d->sorting = (d->sorting & ~QDir::SortByMask) | QDir::Time;
467 d->actionCollection->action("by date")->setChecked(true);
470 void KDirOperator::sortByType()
472 d->sorting = (d->sorting & ~QDir::SortByMask) | QDir::Type;
473 d->actionCollection->action("by type")->setChecked(true);
476 void KDirOperator::sortReversed()
478 if (d->sorting & QDir::Reversed) {
479 d->sorting = d->sorting & ~QDir::Reversed;
480 d->actionCollection->action("descending")->setChecked(false);
481 } else {
482 d->sorting = d->sorting | QDir::Reversed;
483 d->actionCollection->action("descending")->setChecked(true);
487 void KDirOperator::toggleDirsFirst()
489 // TODO: not offered yet
492 void KDirOperator::toggleIgnoreCase()
494 if (d->proxyModel != 0) {
495 Qt::CaseSensitivity cs = d->proxyModel->sortCaseSensitivity();
496 cs = (cs == Qt::CaseSensitive) ? Qt::CaseInsensitive : Qt::CaseSensitive;
497 d->proxyModel->setSortCaseSensitivity(cs);
501 void KDirOperator::updateSelectionDependentActions()
503 const bool hasSelection = (d->itemView != 0) &&
504 d->itemView->selectionModel()->hasSelection();
505 d->actionCollection->action("trash")->setEnabled(hasSelection);
506 d->actionCollection->action("delete")->setEnabled(hasSelection);
507 d->actionCollection->action("properties")->setEnabled(hasSelection);
510 void KDirOperator::setPreviewWidget(KPreviewWidgetBase *w)
512 const bool showPreview = (w != 0);
513 if (showPreview) {
514 d->viewKind = (d->viewKind | KFile::PreviewContents);
515 } else {
516 d->viewKind = (d->viewKind & ~KFile::PreviewContents);
519 delete d->preview;
520 d->preview = w;
522 if (w) {
523 d->splitter->addWidget(w);
526 KToggleAction *previewAction = static_cast<KToggleAction*>(d->actionCollection->action("preview"));
527 previewAction->setEnabled(showPreview);
528 previewAction->setChecked(showPreview);
529 setView(static_cast<KFile::FileView>(d->viewKind));
532 KFileItemList KDirOperator::selectedItems() const
534 KFileItemList itemList;
535 if (d->itemView == 0) {
536 return itemList;
539 const QItemSelection selection = d->proxyModel->mapSelectionToSource(d->itemView->selectionModel()->selection());
541 const QModelIndexList indexList = selection.indexes();
542 foreach(const QModelIndex &index, indexList) {
543 KFileItem item = d->dirModel->itemForIndex(index);
544 if (!item.isNull()) {
545 itemList.append(item);
549 return itemList;
552 bool KDirOperator::isSelected(const KFileItem &item) const
554 if ((item.isNull()) || (d->itemView == 0)) {
555 return false;
558 const QModelIndex dirIndex = d->dirModel->indexForItem(item);
559 const QModelIndex proxyIndex = d->proxyModel->mapFromSource(dirIndex);
560 return d->itemView->selectionModel()->isSelected(proxyIndex);
563 int KDirOperator::numDirs() const
565 return (d->dirLister == 0) ? 0 : d->dirLister->directories().count();
568 int KDirOperator::numFiles() const
570 return (d->dirLister == 0) ? 0 : d->dirLister->items().count() - numDirs();
573 KCompletion * KDirOperator::completionObject() const
575 return const_cast<KCompletion *>(&d->completion);
578 KCompletion *KDirOperator::dirCompletionObject() const
580 return const_cast<KCompletion *>(&d->dirCompletion);
583 KActionCollection * KDirOperator::actionCollection() const
585 return d->actionCollection;
588 KFile::FileView KDirOperator::Private::allViews() {
589 return static_cast<KFile::FileView>(KFile::Simple | KFile::Detail | KFile::Tree | KFile::DetailTree);
592 void KDirOperator::Private::_k_slotDetailedView()
594 KFile::FileView view = static_cast<KFile::FileView>((viewKind & ~allViews()) | KFile::Detail);
595 parent->setView(view);
598 void KDirOperator::Private::_k_slotSimpleView()
600 KFile::FileView view = static_cast<KFile::FileView>((viewKind & ~allViews()) | KFile::Simple);
601 parent->setView(view);
604 void KDirOperator::Private::_k_slotTreeView()
606 KFile::FileView view = static_cast<KFile::FileView>((viewKind & ~allViews()) | KFile::Tree);
607 parent->setView(view);
610 void KDirOperator::Private::_k_slotDetailedTreeView()
612 KFile::FileView view = static_cast<KFile::FileView>((viewKind & ~allViews()) | KFile::DetailTree);
613 parent->setView(view);
616 void KDirOperator::Private::_k_slotToggleHidden(bool show)
618 dirLister->setShowingDotFiles(show);
619 parent->updateDir();
620 _k_assureVisibleSelection();
623 void KDirOperator::Private::_k_togglePreview(bool on)
625 if (on) {
626 viewKind = viewKind | KFile::PreviewContents;
627 if (preview == 0) {
628 preview = new KFileMetaPreview(parent);
629 actionCollection->action("preview")->setChecked(true);
630 splitter->addWidget(preview);
633 preview->show();
635 QMetaObject::invokeMethod(parent, "_k_assureVisibleSelection", Qt::QueuedConnection);
636 if (itemView != 0) {
637 const QModelIndex index = itemView->selectionModel()->currentIndex();
638 if (index.isValid()) {
639 _k_triggerPreview(index);
642 } else if (preview != 0) {
643 viewKind = viewKind & ~KFile::PreviewContents;
644 preview->hide();
648 void KDirOperator::Private::_k_toggleInlinePreviews(bool show)
650 if (showPreviews == show) {
651 return;
654 showPreviews = show;
656 if (!previewGenerator) {
657 return;
660 previewGenerator->setPreviewShown(show);
662 if (!show) {
663 // remove all generated previews
664 QAbstractItemModel *model = dirModel;
665 for (int i = 0; i < model->rowCount(); ++i) {
666 QModelIndex index = model->index(i, 0);
667 const KFileItem item = dirModel->itemForIndex(index);
668 const_cast<QAbstractItemModel*>(index.model())->setData(index, KIcon(item.iconName()), Qt::DecorationRole);
673 void KDirOperator::Private::_k_slotSortByName()
675 parent->sortByName();
676 triggerSorting();
679 void KDirOperator::Private::_k_slotSortBySize()
681 parent->sortBySize();
682 triggerSorting();
685 void KDirOperator::Private::_k_slotSortByDate()
687 parent->sortByDate();
688 triggerSorting();
691 void KDirOperator::Private::_k_slotSortByType()
693 parent->sortByType();
694 triggerSorting();
697 void KDirOperator::Private::_k_slotSortReversed(bool doReverse)
699 if (doReverse) {
700 sorting |= QDir::Reversed;
702 else {
703 sorting &= ~QDir::Reversed;
706 triggerSorting();
709 void KDirOperator::Private::_k_slotToggleDirsFirst()
711 // TODO: port to Qt4's QAbstractItemView
712 /*if ( !d->fileView )
713 return;
715 QDir::SortFlags sorting = d->fileView->sorting();
716 if ( !KFile::isSortDirsFirst( sorting ) )
717 d->fileView->setSorting( sorting | QDir::DirsFirst );
718 else
719 d->fileView->setSorting( sorting & ~QDir::DirsFirst );
720 d->sorting = d->fileView->sorting();*/
723 void KDirOperator::Private::_k_slotToggleIgnoreCase()
725 // TODO: port to Qt4's QAbstractItemView
726 /*if ( !d->fileView )
727 return;
729 QDir::SortFlags sorting = d->fileView->sorting();
730 if ( !KFile::isSortCaseInsensitive( sorting ) )
731 d->fileView->setSorting( sorting | QDir::IgnoreCase );
732 else
733 d->fileView->setSorting( sorting & ~QDir::IgnoreCase );
734 d->sorting = d->fileView->sorting();*/
737 void KDirOperator::mkdir()
739 bool ok;
740 QString where = url().pathOrUrl();
741 QString name = i18n("New Folder");
742 #ifdef Q_WS_WIN
743 if (url().isLocalFile() && QFileInfo(url().toLocalFile() + name).exists())
744 #else
745 if (url().isLocalFile() && QFileInfo(url().path(KUrl::AddTrailingSlash) + name).exists())
746 #endif
747 name = KIO::RenameDialog::suggestName(url(), name);
749 QString folder = KInputDialog::getText(i18n("New Folder"),
750 i18n("Create new folder in:\n%1" , where),
751 name, &ok, this);
752 if (ok)
753 KDirOperator::mkdir(KIO::encodeFileName(folder), true);
756 bool KDirOperator::mkdir(const QString& directory, bool enterDirectory)
758 // Creates "directory", relative to the current directory (d->currUrl).
759 // The given path may contain any number directories, existent or not.
760 // They will all be created, if possible.
762 bool writeOk = false;
763 bool exists = false;
764 KUrl url(d->currUrl);
766 const QStringList dirs = directory.split(QDir::separator(), QString::SkipEmptyParts);
767 QStringList::ConstIterator it = dirs.begin();
769 for (; it != dirs.end(); ++it) {
770 url.addPath(*it);
771 exists = KIO::NetAccess::exists(url, KIO::NetAccess::DestinationSide, 0);
772 writeOk = !exists && KIO::NetAccess::mkdir(url, topLevelWidget());
775 if (exists) { // url was already existent
776 KMessageBox::sorry(d->itemView, i18n("A file or folder named %1 already exists.", url.pathOrUrl()));
777 enterDirectory = false;
778 } else if (!writeOk) {
779 KMessageBox::sorry(d->itemView, i18n("You do not have permission to "
780 "create that folder."));
781 } else if (enterDirectory) {
782 setUrl(url, true);
785 return writeOk;
788 KIO::DeleteJob * KDirOperator::del(const KFileItemList& items,
789 QWidget *parent,
790 bool ask, bool showProgress)
792 if (items.isEmpty()) {
793 KMessageBox::information(parent,
794 i18n("You did not select a file to delete."),
795 i18n("Nothing to Delete"));
796 return 0L;
799 if (parent == 0) {
800 parent = this;
803 KUrl::List urls;
804 QStringList files;
805 foreach (const KFileItem &item, items) {
806 const KUrl url = item.url();
807 urls.append(url);
808 files.append(url.pathOrUrl());
811 bool doIt = !ask;
812 if (ask) {
813 int ret;
814 if (items.count() == 1) {
815 ret = KMessageBox::warningContinueCancel(parent,
816 i18n("<qt>Do you really want to delete\n <b>'%1'</b>?</qt>" ,
817 files.first()),
818 i18n("Delete File"),
819 KStandardGuiItem::del(),
820 KStandardGuiItem::cancel(), "AskForDelete");
821 } else
822 ret = KMessageBox::warningContinueCancelList(parent,
823 i18np("Do you really want to delete this item?", "Do you really want to delete these %1 items?", items.count()),
824 files,
825 i18n("Delete Files"),
826 KStandardGuiItem::del(),
827 KStandardGuiItem::cancel(), "AskForDelete");
828 doIt = (ret == KMessageBox::Continue);
831 if (doIt) {
832 KIO::JobFlags flags = showProgress ? KIO::DefaultFlags : KIO::HideProgressInfo;
833 KIO::DeleteJob *job = KIO::del(urls, flags);
834 job->ui()->setWindow(topLevelWidget());
835 job->ui()->setAutoErrorHandlingEnabled(true);
836 return job;
839 return 0L;
842 void KDirOperator::deleteSelected()
844 const KFileItemList list = selectedItems();
845 if (!list.isEmpty()) {
846 del(list, this);
850 KIO::CopyJob * KDirOperator::trash(const KFileItemList& items,
851 QWidget *parent,
852 bool ask, bool showProgress)
854 if (items.isEmpty()) {
855 KMessageBox::information(parent,
856 i18n("You did not select a file to trash."),
857 i18n("Nothing to Trash"));
858 return 0L;
861 KUrl::List urls;
862 QStringList files;
863 foreach (const KFileItem &item, items) {
864 const KUrl url = item.url();
865 urls.append(url);
866 files.append(url.pathOrUrl());
869 bool doIt = !ask;
870 if (ask) {
871 int ret;
872 if (items.count() == 1) {
873 ret = KMessageBox::warningContinueCancel(parent,
874 i18n("<qt>Do you really want to trash\n <b>'%1'</b>?</qt>" ,
875 files.first()),
876 i18n("Trash File"),
877 KGuiItem(i18nc("to trash", "&Trash"), "user-trash"),
878 KStandardGuiItem::cancel(), "AskForTrash");
879 } else
880 ret = KMessageBox::warningContinueCancelList(parent,
881 i18np("translators: not called for n == 1", "Do you really want to trash these %1 items?", items.count()),
882 files,
883 i18n("Trash Files"),
884 KGuiItem(i18nc("to trash", "&Trash"), "user-trash"),
885 KStandardGuiItem::cancel(), "AskForTrash");
886 doIt = (ret == KMessageBox::Continue);
889 if (doIt) {
890 KIO::JobFlags flags = showProgress ? KIO::DefaultFlags : KIO::HideProgressInfo;
891 KIO::CopyJob *job = KIO::trash(urls, flags);
892 job->ui()->setWindow(topLevelWidget());
893 job->ui()->setAutoErrorHandlingEnabled(true);
894 return job;
897 return 0L;
900 KFilePreviewGenerator *KDirOperator::previewGenerator() const
902 return d->previewGenerator;
905 void KDirOperator::setInlinePreviewShown(bool show)
907 d->inlinePreviewState = show ? Private::ForcedToTrue : Private::ForcedToFalse;
910 bool KDirOperator::isInlinePreviewShown() const
912 return d->showPreviews;
915 int KDirOperator::iconsZoom() const
917 return d->iconsZoom;
920 void KDirOperator::setIsSaving(bool isSaving)
922 d->isSaving = isSaving;
925 bool KDirOperator::isSaving() const
927 return d->isSaving;
930 void KDirOperator::trashSelected()
932 if (d->itemView == 0) {
933 return;
936 if (QApplication::keyboardModifiers() & Qt::ShiftModifier) {
937 deleteSelected();
938 return;
941 const KFileItemList list = selectedItems();
942 if (!list.isEmpty()) {
943 trash(list, this);
947 void KDirOperator::setIconsZoom(int _value)
949 if (d->iconsZoom == _value) {
950 return;
953 int value = _value;
954 value = qMin(100, value);
955 value = qMax(0, value);
957 d->iconsZoom = value;
959 if (d->configGroup && d->inlinePreviewState == Private::NotForced) {
960 if (qobject_cast<QListView*>(d->itemView)) {
961 d->configGroup->writeEntry("listViewIconSize", d->iconsZoom);
962 } else {
963 d->configGroup->writeEntry("detailedViewIconSize", d->iconsZoom);
967 if (!d->previewGenerator) {
968 return;
971 const int maxSize = KIconLoader::SizeEnormous - KIconLoader::SizeSmall;
972 const int val = (maxSize * value / 100) + KIconLoader::SizeSmall;
973 d->itemView->setIconSize(QSize(val, val));
974 d->updateListViewGrid();
975 d->previewGenerator->updatePreviews();
977 emit currentIconSizeChanged(value);
980 void KDirOperator::close()
982 resetCursor();
983 d->pendingMimeTypes.clear();
984 d->completion.clear();
985 d->dirCompletion.clear();
986 d->completeListDirty = true;
987 d->dirLister->stop();
990 void KDirOperator::Private::checkPath(const QString &, bool /*takeFiles*/) // SLOT
992 #if 0
993 // copy the argument in a temporary string
994 QString text = _txt;
995 // it's unlikely to happen, that at the beginning are spaces, but
996 // for the end, it happens quite often, I guess.
997 text = text.trimmed();
998 // if the argument is no URL (the check is quite fragil) and it's
999 // no absolute path, we add the current directory to get a correct url
1000 if (text.find(':') < 0 && text[0] != '/')
1001 text.insert(0, d->currUrl);
1003 // in case we have a selection defined and someone patched the file-
1004 // name, we check, if the end of the new name is changed.
1005 if (!selection.isNull()) {
1006 int position = text.lastIndexOf('/');
1007 ASSERT(position >= 0); // we already inserted the current d->dirLister in case
1008 QString filename = text.mid(position + 1, text.length());
1009 if (filename != selection)
1010 selection.clear();
1013 KUrl u(text); // I have to take care of entered URLs
1014 bool filenameEntered = false;
1016 if (u.isLocalFile()) {
1017 // the empty path is kind of a hack
1018 KFileItem i("", u.toLocalFile());
1019 if (i.isDir())
1020 setUrl(text, true);
1021 else {
1022 if (takeFiles)
1023 if (acceptOnlyExisting && !i.isFile())
1024 warning("you entered an invalid URL");
1025 else
1026 filenameEntered = true;
1028 } else
1029 setUrl(text, true);
1031 if (filenameEntered) {
1032 filename_ = u.url();
1033 emit fileSelected(filename_);
1035 QApplication::restoreOverrideCursor();
1037 accept();
1039 #endif
1040 kDebug(kfile_area) << "TODO KDirOperator::checkPath()";
1043 void KDirOperator::setUrl(const KUrl& _newurl, bool clearforward)
1045 KUrl newurl;
1047 if (!_newurl.isValid())
1048 newurl.setPath(QDir::homePath());
1049 else
1050 newurl = _newurl;
1052 newurl.adjustPath( KUrl::AddTrailingSlash );
1053 #ifdef Q_WS_WIN
1054 QString pathstr = QDir::fromNativeSeparators(newurl.toLocalFile());
1055 #else
1056 QString pathstr = newurl.path();
1057 #endif
1058 newurl.setPath(pathstr);
1060 // already set
1061 if (newurl.equals(d->currUrl, KUrl::CompareWithoutTrailingSlash))
1062 return;
1064 if (!Private::isReadable(newurl)) {
1065 // maybe newurl is a file? check its parent directory
1066 newurl.setPath(newurl.directory());
1067 if (newurl.equals(d->currUrl, KUrl::CompareWithoutTrailingSlash))
1068 return; // parent is current dir, nothing to do (fixes #173454, too)
1069 KIO::UDSEntry entry;
1070 bool res = KIO::NetAccess::stat(newurl, entry, this);
1071 KFileItem i(entry, newurl);
1072 if ((!res || !Private::isReadable(newurl)) && i.isDir()) {
1073 resetCursor();
1074 KMessageBox::error(d->itemView,
1075 i18n("The specified folder does not exist "
1076 "or was not readable."));
1077 return;
1078 } else if (!i.isDir()) {
1079 return;
1083 if (clearforward) {
1084 // autodelete should remove this one
1085 d->backStack.push(new KUrl(d->currUrl));
1086 qDeleteAll(d->forwardStack);
1087 d->forwardStack.clear();
1090 d->lastURL = d->currUrl.url(KUrl::RemoveTrailingSlash);
1091 d->currUrl = newurl;
1093 pathChanged();
1094 emit urlEntered(newurl);
1096 // enable/disable actions
1097 QAction* forwardAction = d->actionCollection->action("forward");
1098 forwardAction->setEnabled(!d->forwardStack.isEmpty());
1100 QAction* backAction = d->actionCollection->action("back");
1101 backAction->setEnabled(!d->backStack.isEmpty());
1103 QAction* upAction = d->actionCollection->action("up");
1104 upAction->setEnabled(!isRoot());
1106 d->openUrl(newurl);
1109 void KDirOperator::updateDir()
1111 QApplication::setOverrideCursor(Qt::WaitCursor);
1112 d->dirLister->emitChanges();
1113 QApplication::restoreOverrideCursor();
1116 void KDirOperator::rereadDir()
1118 pathChanged();
1119 d->openUrl(d->currUrl, KDirLister::Reload);
1123 bool KDirOperator::Private::openUrl(const KUrl& url, KDirLister::OpenUrlFlags flags)
1125 bool result = dirLister->openUrl(url, flags);
1126 if (!result) // in that case, neither completed() nor canceled() will be emitted by KDL
1127 _k_slotCanceled();
1129 return result;
1132 int KDirOperator::Private::sortColumn() const
1134 int column = KDirModel::Name;
1135 if (KFile::isSortByDate(sorting)) {
1136 column = KDirModel::ModifiedTime;
1137 } else if (KFile::isSortBySize(sorting)) {
1138 column = KDirModel::Size;
1139 } else if (KFile::isSortByType(sorting)) {
1140 column = KDirModel::Type;
1141 } else {
1142 Q_ASSERT(KFile::isSortByName(sorting));
1145 return column;
1148 Qt::SortOrder KDirOperator::Private::sortOrder() const
1150 return (sorting & QDir::Reversed) ? Qt::DescendingOrder :
1151 Qt::AscendingOrder;
1154 void KDirOperator::Private::triggerSorting()
1156 proxyModel->sort(sortColumn(), sortOrder());
1158 // TODO: The headers from QTreeView don't take care about a sorting
1159 // change of the proxy model hence they must be updated the manually.
1160 // This is done here by a qobject_cast, but it would be nicer to:
1161 // - provide a signal 'sortingChanged()'
1162 // - connect KDirOperatorDetailView() with this signal and update the
1163 // header internally
1164 QTreeView* treeView = qobject_cast<QTreeView*>(itemView);
1165 if (treeView != 0) {
1166 QHeaderView* headerView = treeView->header();
1167 headerView->blockSignals(true);
1168 headerView->setSortIndicator(sortColumn(), sortOrder());
1169 headerView->blockSignals(false);
1172 _k_assureVisibleSelection();
1175 // Protected
1176 void KDirOperator::pathChanged()
1178 if (d->itemView == 0)
1179 return;
1181 d->pendingMimeTypes.clear();
1182 //d->fileView->clear(); TODO
1183 d->completion.clear();
1184 d->dirCompletion.clear();
1186 // it may be, that we weren't ready at this time
1187 QApplication::restoreOverrideCursor();
1189 // when KIO::Job emits finished, the slot will restore the cursor
1190 QApplication::setOverrideCursor(Qt::WaitCursor);
1192 if (!Private::isReadable(d->currUrl)) {
1193 KMessageBox::error(d->itemView,
1194 i18n("The specified folder does not exist "
1195 "or was not readable."));
1196 if (d->backStack.isEmpty())
1197 home();
1198 else
1199 back();
1203 void KDirOperator::Private::_k_slotRedirected(const KUrl& newURL)
1205 currUrl = newURL;
1206 pendingMimeTypes.clear();
1207 completion.clear();
1208 dirCompletion.clear();
1209 completeListDirty = true;
1210 emit parent->urlEntered(newURL);
1213 // Code pinched from kfm then hacked
1214 void KDirOperator::back()
1216 if (d->backStack.isEmpty())
1217 return;
1219 d->forwardStack.push(new KUrl(d->currUrl));
1221 KUrl *s = d->backStack.pop();
1223 setUrl(*s, false);
1224 delete s;
1227 // Code pinched from kfm then hacked
1228 void KDirOperator::forward()
1230 if (d->forwardStack.isEmpty())
1231 return;
1233 d->backStack.push(new KUrl(d->currUrl));
1235 KUrl *s = d->forwardStack.pop();
1236 setUrl(*s, false);
1237 delete s;
1240 KUrl KDirOperator::url() const
1242 return d->currUrl;
1245 void KDirOperator::cdUp()
1247 KUrl tmp(d->currUrl);
1248 tmp.cd(QLatin1String(".."));
1249 setUrl(tmp, true);
1252 void KDirOperator::home()
1254 KUrl u;
1255 u.setPath(QDir::homePath());
1256 setUrl(u, true);
1259 void KDirOperator::clearFilter()
1261 d->dirLister->setNameFilter(QString());
1262 d->dirLister->clearMimeFilter();
1263 checkPreviewSupport();
1266 void KDirOperator::setNameFilter(const QString& filter)
1268 d->dirLister->setNameFilter(filter);
1269 checkPreviewSupport();
1272 QString KDirOperator::nameFilter() const
1274 return d->dirLister->nameFilter();
1277 void KDirOperator::setMimeFilter(const QStringList& mimetypes)
1279 d->dirLister->setMimeFilter(mimetypes);
1280 checkPreviewSupport();
1283 QStringList KDirOperator::mimeFilter() const
1285 return d->dirLister->mimeFilters();
1288 bool KDirOperator::checkPreviewSupport()
1290 KToggleAction *previewAction = static_cast<KToggleAction*>(d->actionCollection->action("preview"));
1292 bool hasPreviewSupport = false;
1293 KConfigGroup cg(KGlobal::config(), ConfigGroup);
1294 if (cg.readEntry("Show Default Preview", true))
1295 hasPreviewSupport = d->checkPreviewInternal();
1297 previewAction->setEnabled(hasPreviewSupport);
1298 return hasPreviewSupport;
1301 void KDirOperator::activatedMenu(const KFileItem &item, const QPoint &pos)
1303 Q_UNUSED(item);
1304 setupMenu();
1305 updateSelectionDependentActions();
1307 emit contextMenuAboutToShow( item, d->actionMenu->menu() );
1309 d->actionMenu->menu()->exec(pos);
1312 void KDirOperator::changeEvent(QEvent *event)
1314 QWidget::changeEvent(event);
1317 bool KDirOperator::eventFilter(QObject *watched, QEvent *event)
1319 Q_UNUSED(watched);
1321 // If we are not hovering any items, check if there is a current index
1322 // set. In that case, we show the preview of that item.
1323 switch(event->type()) {
1324 case QEvent::MouseMove: {
1325 if (d->preview) {
1326 const QModelIndex hoveredIndex = d->itemView->indexAt(d->itemView->viewport()->mapFromGlobal(QCursor::pos()));
1328 if (d->lastHoveredIndex == hoveredIndex)
1329 return false;
1331 d->lastHoveredIndex = hoveredIndex;
1333 const QModelIndex focusedIndex = d->itemView->selectionModel() ? d->itemView->selectionModel()->currentIndex()
1334 : QModelIndex();
1336 if (!hoveredIndex.isValid() && focusedIndex.isValid() &&
1337 d->itemView->selectionModel()->isSelected(focusedIndex) &&
1338 (d->lastHoveredIndex != focusedIndex)) {
1339 const QModelIndex sourceFocusedIndex = d->proxyModel->mapToSource(focusedIndex);
1340 const KFileItem item = d->dirModel->itemForIndex(sourceFocusedIndex);
1341 if (!item.isNull()) {
1342 d->preview->showPreview(item.url());
1347 break;
1348 case QEvent::MouseButtonRelease: {
1349 if (d->preview != 0) {
1350 const QModelIndex hoveredIndex = d->itemView->indexAt(d->itemView->viewport()->mapFromGlobal(QCursor::pos()));
1351 const QModelIndex focusedIndex = d->itemView->selectionModel() ? d->itemView->selectionModel()->currentIndex()
1352 : QModelIndex();
1354 if (((!focusedIndex.isValid()) ||
1355 !d->itemView->selectionModel()->isSelected(focusedIndex)) &&
1356 (!hoveredIndex.isValid())) {
1357 d->preview->clearPreview();
1361 break;
1362 case QEvent::Wheel: {
1363 QWheelEvent *evt = static_cast<QWheelEvent*>(event);
1364 if (evt->modifiers() & Qt::ControlModifier) {
1365 if (evt->delta() > 0) {
1366 setIconsZoom(d->iconsZoom + 10);
1367 } else {
1368 setIconsZoom(d->iconsZoom - 10);
1370 return true;
1373 break;
1374 default:
1375 break;
1378 return false;
1381 bool KDirOperator::Private::checkPreviewInternal() const
1383 const QStringList supported = KIO::PreviewJob::supportedMimeTypes();
1384 // no preview support for directories?
1385 if (parent->dirOnlyMode() && supported.indexOf("inode/directory") == -1)
1386 return false;
1388 QStringList mimeTypes = dirLister->mimeFilters();
1389 const QStringList nameFilter = dirLister->nameFilter().split(' ', QString::SkipEmptyParts);
1391 if (mimeTypes.isEmpty() && nameFilter.isEmpty() && !supported.isEmpty())
1392 return true;
1393 else {
1394 QRegExp r;
1395 r.setPatternSyntax(QRegExp::Wildcard); // the "mimetype" can be "image/*"
1397 if (!mimeTypes.isEmpty()) {
1398 QStringList::ConstIterator it = supported.begin();
1400 for (; it != supported.end(); ++it) {
1401 r.setPattern(*it);
1403 QStringList result = mimeTypes.filter(r);
1404 if (!result.isEmpty()) { // matches! -> we want previews
1405 return true;
1410 if (!nameFilter.isEmpty()) {
1411 // find the mimetypes of all the filter-patterns
1412 QStringList::const_iterator it1 = nameFilter.begin();
1413 for (; it1 != nameFilter.end(); ++it1) {
1414 if ((*it1) == "*") {
1415 return true;
1418 KMimeType::Ptr mt = KMimeType::findByPath(*it1, 0, true /*fast mode, no file contents exist*/);
1419 if (!mt)
1420 continue;
1421 QString mime = mt->name();
1423 // the "mimetypes" we get from the PreviewJob can be "image/*"
1424 // so we need to check in wildcard mode
1425 QStringList::ConstIterator it2 = supported.begin();
1426 for (; it2 != supported.end(); ++it2) {
1427 r.setPattern(*it2);
1428 if (r.indexIn(mime) != -1) {
1429 return true;
1436 return false;
1439 QAbstractItemView* KDirOperator::createView(QWidget* parent, KFile::FileView viewKind)
1441 QAbstractItemView *itemView = 0;
1442 if (KFile::isDetailView(viewKind) || KFile::isTreeView(viewKind) || KFile::isDetailTreeView(viewKind)) {
1443 KDirOperatorDetailView *detailView = new KDirOperatorDetailView(parent);
1444 detailView->setViewMode(viewKind);
1445 connect(detailView->header(), SIGNAL(sortIndicatorChanged (int, Qt::SortOrder)),
1446 this, SLOT(_k_synchronizeSortingState(int, Qt::SortOrder)));
1447 itemView = detailView;
1448 } else {
1449 itemView = new KDirOperatorIconView(parent);
1452 return itemView;
1455 void KDirOperator::setAcceptDrops(bool b)
1457 // TODO:
1458 //if (d->fileView)
1459 // d->fileView->widget()->setAcceptDrops(b);
1460 QWidget::setAcceptDrops(b);
1463 void KDirOperator::setDropOptions(int options)
1465 d->dropOptions = options;
1466 // TODO:
1467 //if (d->fileView)
1468 // d->fileView->setDropOptions(options);
1471 void KDirOperator::setView(KFile::FileView viewKind)
1473 bool preview = (KFile::isPreviewInfo(viewKind) || KFile::isPreviewContents(viewKind));
1475 if (viewKind == KFile::Default) {
1476 if (KFile::isDetailView((KFile::FileView)d->defaultView)) {
1477 viewKind = KFile::Detail;
1478 } else if (KFile::isTreeView((KFile::FileView)d->defaultView)) {
1479 viewKind = KFile::Tree;
1480 } else if (KFile::isDetailTreeView((KFile::FileView)d->defaultView)) {
1481 viewKind = KFile::DetailTree;
1482 } else {
1483 viewKind = KFile::Simple;
1486 const KFile::FileView defaultViewKind = static_cast<KFile::FileView>(d->defaultView);
1487 preview = (KFile::isPreviewInfo(defaultViewKind) || KFile::isPreviewContents(defaultViewKind))
1488 && d->actionCollection->action("preview")->isEnabled();
1491 d->viewKind = static_cast<int>(viewKind);
1492 viewKind = static_cast<KFile::FileView>(d->viewKind);
1494 QAbstractItemView *newView = createView(this, viewKind);
1495 setView(newView);
1497 d->_k_togglePreview(preview);
1500 QAbstractItemView * KDirOperator::view() const
1502 return d->itemView;
1505 KFile::Modes KDirOperator::mode() const
1507 return d->mode;
1510 void KDirOperator::setMode(KFile::Modes mode)
1512 if (d->mode == mode)
1513 return;
1515 d->mode = mode;
1517 d->dirLister->setDirOnlyMode(dirOnlyMode());
1519 // reset the view with the different mode
1520 setView(static_cast<KFile::FileView>(d->viewKind));
1523 void KDirOperator::setView(QAbstractItemView *view)
1525 if (view == d->itemView) {
1526 return;
1529 // TODO: do a real timer and restart it after that
1530 d->pendingMimeTypes.clear();
1531 const bool listDir = (d->itemView == 0);
1533 if (d->mode & KFile::Files) {
1534 view->setSelectionMode(QAbstractItemView::ExtendedSelection);
1535 } else {
1536 view->setSelectionMode(QAbstractItemView::SingleSelection);
1539 QItemSelectionModel *selectionModel = 0;
1540 if ((d->itemView != 0) && d->itemView->selectionModel()->hasSelection()) {
1541 // remember the selection of the current item view and apply this selection
1542 // to the new view later
1543 const QItemSelection selection = d->itemView->selectionModel()->selection();
1544 selectionModel = new QItemSelectionModel(d->proxyModel, this);
1545 selectionModel->select(selection, QItemSelectionModel::Select);
1548 setFocusProxy(0);
1549 delete d->itemView;
1550 d->itemView = view;
1551 d->itemView->setModel(d->proxyModel);
1552 setFocusProxy(d->itemView);
1554 view->viewport()->installEventFilter(this);
1556 KFileItemDelegate *delegate = new KFileItemDelegate(d->itemView);
1557 d->itemView->setItemDelegate(delegate);
1558 d->itemView->viewport()->setAttribute(Qt::WA_Hover);
1559 d->itemView->setContextMenuPolicy(Qt::CustomContextMenu);
1560 d->itemView->setMouseTracking(true);
1561 //d->itemView->setDropOptions(d->dropOptions);
1563 connect(d->itemView, SIGNAL(activated(const QModelIndex&)),
1564 this, SLOT(_k_slotActivated(const QModelIndex&)));
1565 connect(d->itemView, SIGNAL(doubleClicked(const QModelIndex&)),
1566 this, SLOT(_k_slotDoubleClicked(const QModelIndex&)));
1567 connect(d->itemView, SIGNAL(pressed(const QModelIndex&)),
1568 this, SLOT(_k_slotPressed(const QModelIndex&)));
1569 connect(d->itemView, SIGNAL(customContextMenuRequested(const QPoint&)),
1570 this, SLOT(_k_openContextMenu(const QPoint&)));
1571 connect(d->itemView, SIGNAL(entered(const QModelIndex&)),
1572 this, SLOT(_k_triggerPreview(const QModelIndex&)));
1573 // assure that the sorting state d->sorting matches with the current action
1574 const bool descending = d->actionCollection->action("descending")->isChecked();
1575 if (descending) {
1576 d->sorting = d->sorting | QDir::Reversed;
1577 } else {
1578 d->sorting = d->sorting & ~QDir::Reversed;
1580 d->triggerSorting();
1582 updateViewActions();
1583 d->splitter->insertWidget(0, d->itemView);
1585 d->splitter->resize(size());
1586 d->itemView->show();
1588 if (listDir) {
1589 QApplication::setOverrideCursor(Qt::WaitCursor);
1590 d->openUrl(d->currUrl);
1593 if (selectionModel != 0) {
1594 d->itemView->setSelectionModel(selectionModel);
1595 QMetaObject::invokeMethod(this, "_k_assureVisibleSelection", Qt::QueuedConnection);
1598 connect(d->itemView->selectionModel(),
1599 SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)),
1600 this, SLOT(_k_triggerPreview(const QModelIndex&)));
1601 connect(d->itemView->selectionModel(),
1602 SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
1603 this, SLOT(_k_slotSelectionChanged()));
1605 // if we cannot cast it to a QListView, disable the "Icon Position" menu. Note that this check
1606 // needs to be done here, and not in createView, since we can be set an external view
1607 d->decorationMenu->setEnabled(qobject_cast<QListView*>(d->itemView));
1609 d->shouldFetchForItems = qobject_cast<QTreeView*>(view);
1610 if (d->shouldFetchForItems) {
1611 connect(d->dirModel, SIGNAL(expand(QModelIndex)), this, SLOT(_k_slotExpandToUrl(QModelIndex)));
1612 } else {
1613 d->itemsToBeSetAsCurrent.clear();
1616 const bool previewForcedToTrue = d->inlinePreviewState == Private::ForcedToTrue;
1617 const bool previewShown = d->inlinePreviewState == Private::NotForced ? d->showPreviews : previewForcedToTrue;
1618 d->previewGenerator = new KFilePreviewGenerator(d->itemView);
1619 const int maxSize = KIconLoader::SizeEnormous - KIconLoader::SizeSmall;
1620 const int val = (maxSize * d->iconsZoom / 100) + KIconLoader::SizeSmall;
1621 d->itemView->setIconSize(previewForcedToTrue ? QSize(KIconLoader::SizeHuge, KIconLoader::SizeHuge) : QSize(val, val));
1622 d->previewGenerator->setPreviewShown(previewShown);
1623 d->actionCollection->action("inline preview")->setChecked(previewShown);
1625 // ensure we change everything needed
1626 d->_k_slotChangeDecorationPosition();
1628 emit viewChanged(view);
1630 const int zoom = previewForcedToTrue ? (KIconLoader::SizeHuge - KIconLoader::SizeSmall + 1) * 100 / maxSize : d->iconSizeForViewType(view);
1632 // this will make d->iconsZoom be updated, since setIconsZoom slot will be called
1633 emit currentIconSizeChanged(zoom);
1636 void KDirOperator::setDirLister(KDirLister *lister)
1638 if (lister == d->dirLister) // sanity check
1639 return;
1641 delete d->dirModel;
1642 d->dirModel = 0;
1644 delete d->proxyModel;
1645 d->proxyModel = 0;
1647 //delete d->dirLister; // deleted by KDirModel already, which took ownership
1648 d->dirLister = lister;
1650 d->dirModel = new KDirModel();
1651 d->dirModel->setDirLister(d->dirLister);
1652 d->dirModel->setDropsAllowed(KDirModel::DropOnDirectory);
1654 d->shouldFetchForItems = qobject_cast<QTreeView*>(d->itemView);
1655 if (d->shouldFetchForItems) {
1656 connect(d->dirModel, SIGNAL(expand(QModelIndex)), this, SLOT(_k_slotExpandToUrl(QModelIndex)));
1657 } else {
1658 d->itemsToBeSetAsCurrent.clear();
1661 d->proxyModel = new KDirSortFilterProxyModel(this);
1662 d->proxyModel->setSourceModel(d->dirModel);
1664 d->dirLister->setAutoUpdate(true);
1665 d->dirLister->setDelayedMimeTypes(true);
1667 QWidget* mainWidget = topLevelWidget();
1668 d->dirLister->setMainWindow(mainWidget);
1669 kDebug(kfile_area) << "mainWidget=" << mainWidget;
1671 connect(d->dirLister, SIGNAL(percent(int)),
1672 SLOT(_k_slotProgress(int)));
1673 connect(d->dirLister, SIGNAL(started(const KUrl&)), SLOT(_k_slotStarted()));
1674 connect(d->dirLister, SIGNAL(completed()), SLOT(_k_slotIOFinished()));
1675 connect(d->dirLister, SIGNAL(canceled()), SLOT(_k_slotCanceled()));
1676 connect(d->dirLister, SIGNAL(redirection(const KUrl&)),
1677 SLOT(_k_slotRedirected(const KUrl&)));
1680 void KDirOperator::selectDir(const KFileItem &item)
1682 setUrl(item.targetUrl(), true);
1685 void KDirOperator::selectFile(const KFileItem &item)
1687 QApplication::restoreOverrideCursor();
1689 emit fileSelected(item);
1692 void KDirOperator::highlightFile(const KFileItem &item)
1694 if ((d->preview != 0) && !item.isNull()) {
1695 d->preview->showPreview(item.url());
1698 emit fileHighlighted(item);
1701 void KDirOperator::setCurrentItem(const QString& url)
1703 kDebug(kfile_area);
1705 KFileItem item = d->dirLister->findByUrl(url);
1706 if (d->shouldFetchForItems && item.isNull()) {
1707 d->itemsToBeSetAsCurrent << url;
1708 d->dirModel->expandToUrl(url);
1709 return;
1712 setCurrentItem(item);
1715 void KDirOperator::setCurrentItem(const KFileItem& item)
1717 kDebug(kfile_area);
1719 if (!d->itemView) {
1720 return;
1723 QItemSelectionModel *selModel = d->itemView->selectionModel();
1724 if (selModel) {
1725 selModel->clear();
1726 if (!item.isNull()) {
1727 const QModelIndex dirIndex = d->dirModel->indexForItem(item);
1728 const QModelIndex proxyIndex = d->proxyModel->mapFromSource(dirIndex);
1729 selModel->setCurrentIndex(proxyIndex, QItemSelectionModel::Select);
1734 void KDirOperator::setCurrentItems(const QStringList& urls)
1736 kDebug(kfile_area);
1738 if (!d->itemView) {
1739 return;
1742 KFileItemList itemList;
1743 foreach (const QString &url, urls) {
1744 KFileItem item = d->dirLister->findByUrl(url);
1745 if (d->shouldFetchForItems && item.isNull()) {
1746 d->itemsToBeSetAsCurrent << url;
1747 d->dirModel->expandToUrl(url);
1748 continue;
1750 itemList << item;
1753 setCurrentItems(itemList);
1756 void KDirOperator::setCurrentItems(const KFileItemList& items)
1758 kDebug(kfile_area);
1760 if (d->itemView == 0) {
1761 return;
1764 QItemSelectionModel *selModel = d->itemView->selectionModel();
1765 if (selModel) {
1766 selModel->clear();
1767 QModelIndex proxyIndex;
1768 foreach (const KFileItem &item, items) {
1769 if (!item.isNull()) {
1770 const QModelIndex dirIndex = d->dirModel->indexForItem(item);
1771 proxyIndex = d->proxyModel->mapFromSource(dirIndex);
1772 selModel->select(proxyIndex, QItemSelectionModel::Select);
1775 if (proxyIndex.isValid()) {
1776 selModel->setCurrentIndex(proxyIndex, QItemSelectionModel::NoUpdate);
1781 QString KDirOperator::makeCompletion(const QString& string)
1783 if (string.isEmpty()) {
1784 d->itemView->selectionModel()->clear();
1785 return QString();
1788 prepareCompletionObjects();
1789 return d->completion.makeCompletion(string);
1792 QString KDirOperator::makeDirCompletion(const QString& string)
1794 if (string.isEmpty()) {
1795 d->itemView->selectionModel()->clear();
1796 return QString();
1799 prepareCompletionObjects();
1800 return d->dirCompletion.makeCompletion(string);
1803 void KDirOperator::prepareCompletionObjects()
1805 if (d->itemView == 0) {
1806 return;
1809 if (d->completeListDirty) { // create the list of all possible completions
1810 const KFileItemList itemList = d->dirLister->items();
1811 foreach (const KFileItem &item, itemList) {
1812 d->completion.addItem(item.name());
1813 if (item.isDir()) {
1814 d->dirCompletion.addItem(item.name());
1817 d->completeListDirty = false;
1821 void KDirOperator::slotCompletionMatch(const QString& match)
1823 setCurrentItem(match);
1824 emit completion(match);
1827 void KDirOperator::setupActions()
1829 d->actionCollection = new KActionCollection(this);
1830 d->actionCollection->setObjectName("KDirOperator::actionCollection");
1832 d->actionMenu = new KActionMenu(i18n("Menu"), this);
1833 d->actionCollection->addAction("popupMenu", d->actionMenu);
1835 QAction* upAction = d->actionCollection->addAction(KStandardAction::Up, "up", this, SLOT(cdUp()));
1836 upAction->setText(i18n("Parent Folder"));
1838 d->actionCollection->addAction(KStandardAction::Back, "back", this, SLOT(back()));
1840 d->actionCollection->addAction(KStandardAction::Forward, "forward", this, SLOT(forward()));
1842 QAction* homeAction = d->actionCollection->addAction(KStandardAction::Home, "home", this, SLOT(home()));
1843 homeAction->setText(i18n("Home Folder"));
1845 KAction* reloadAction = d->actionCollection->addAction(KStandardAction::Redisplay, "reload", this, SLOT(rereadDir()));
1846 reloadAction->setText(i18n("Reload"));
1847 reloadAction->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::Reload));
1849 KAction* mkdirAction = new KAction(i18n("New Folder..."), this);
1850 d->actionCollection->addAction("mkdir", mkdirAction);
1851 mkdirAction->setIcon(KIcon(QLatin1String("folder-new")));
1852 connect(mkdirAction, SIGNAL(triggered(bool)), this, SLOT(mkdir()));
1854 KAction* trash = new KAction(i18n("Move to Trash"), this);
1855 d->actionCollection->addAction("trash", trash);
1856 trash->setIcon(KIcon("user-trash"));
1857 trash->setShortcuts(KShortcut(Qt::Key_Delete));
1858 connect(trash, SIGNAL(triggered(bool)), SLOT(trashSelected()));
1860 KAction* action = new KAction(i18n("Delete"), this);
1861 d->actionCollection->addAction("delete", action);
1862 action->setIcon(KIcon("edit-delete"));
1863 action->setShortcuts(KShortcut(Qt::SHIFT + Qt::Key_Delete));
1864 connect(action, SIGNAL(triggered(bool)), this, SLOT(deleteSelected()));
1866 // the sort menu actions
1867 KActionMenu *sortMenu = new KActionMenu(i18n("Sorting"), this);
1868 d->actionCollection->addAction("sorting menu", sortMenu);
1870 KToggleAction *byNameAction = new KToggleAction(i18n("By Name"), this);
1871 d->actionCollection->addAction("by name", byNameAction);
1872 connect(byNameAction, SIGNAL(triggered(bool)), this, SLOT(_k_slotSortByName()));
1874 KToggleAction *bySizeAction = new KToggleAction(i18n("By Size"), this);
1875 d->actionCollection->addAction("by size", bySizeAction);
1876 connect(bySizeAction, SIGNAL(triggered(bool)), this, SLOT(_k_slotSortBySize()));
1878 KToggleAction *byDateAction = new KToggleAction(i18n("By Date"), this);
1879 d->actionCollection->addAction("by date", byDateAction);
1880 connect(byDateAction, SIGNAL(triggered(bool)), this, SLOT(_k_slotSortByDate()));
1882 KToggleAction *byTypeAction = new KToggleAction(i18n("By Type"), this);
1883 d->actionCollection->addAction("by type", byTypeAction);
1884 connect(byTypeAction, SIGNAL(triggered(bool)), this, SLOT(_k_slotSortByType()));
1886 KToggleAction *descendingAction = new KToggleAction(i18n("Descending"), this);
1887 d->actionCollection->addAction("descending", descendingAction);
1888 connect(descendingAction, SIGNAL(toggled(bool)), this, SLOT(_k_slotSortReversed(bool)));
1890 QActionGroup* sortGroup = new QActionGroup(this);
1891 byNameAction->setActionGroup(sortGroup);
1892 bySizeAction->setActionGroup(sortGroup);
1893 byDateAction->setActionGroup(sortGroup);
1894 byTypeAction->setActionGroup(sortGroup);
1896 d->decorationMenu = new KActionMenu(i18n("Icon Position"), this);
1897 d->actionCollection->addAction("decoration menu", d->decorationMenu);
1899 d->leftAction = new KToggleAction(i18n("Next to File Name"), this);
1900 d->actionCollection->addAction("decorationAtLeft", d->leftAction);
1901 connect(d->leftAction, SIGNAL(triggered(bool)), this, SLOT(_k_slotChangeDecorationPosition()));
1903 KToggleAction *topAction = new KToggleAction(i18n("Above File Name"), this);
1904 d->actionCollection->addAction("decorationAtTop", topAction);
1905 connect(topAction, SIGNAL(triggered(bool)), this, SLOT(_k_slotChangeDecorationPosition()));
1907 d->decorationMenu->addAction(d->leftAction);
1908 d->decorationMenu->addAction(topAction);
1910 QActionGroup* decorationGroup = new QActionGroup(this);
1911 d->leftAction->setActionGroup(decorationGroup);
1912 topAction->setActionGroup(decorationGroup);
1914 KToggleAction *shortAction = new KToggleAction(i18n("Short View"), this);
1915 d->actionCollection->addAction("short view", shortAction);
1916 shortAction->setIcon(KIcon(QLatin1String("view-list-icons")));
1917 connect(shortAction, SIGNAL(triggered()), SLOT(_k_slotSimpleView()));
1919 KToggleAction *detailedAction = new KToggleAction(i18n("Detailed View"), this);
1920 d->actionCollection->addAction("detailed view", detailedAction);
1921 detailedAction->setIcon(KIcon(QLatin1String("view-list-details")));
1922 connect(detailedAction, SIGNAL(triggered ()), SLOT(_k_slotDetailedView()));
1924 KToggleAction *treeAction = new KToggleAction(i18n("Tree View"), this);
1925 d->actionCollection->addAction("tree view", treeAction);
1926 treeAction->setIcon(KIcon(QLatin1String("view-list-tree")));
1927 connect(treeAction, SIGNAL(triggered ()), SLOT(_k_slotTreeView()));
1929 KToggleAction *detailedTreeAction = new KToggleAction(i18n("Detailed Tree View"), this);
1930 d->actionCollection->addAction("detailed tree view", detailedTreeAction);
1931 detailedTreeAction->setIcon(KIcon(QLatin1String("view-list-tree")));
1932 connect(detailedTreeAction, SIGNAL(triggered ()), SLOT(_k_slotDetailedTreeView()));
1934 QActionGroup* viewGroup = new QActionGroup(this);
1935 shortAction->setActionGroup(viewGroup);
1936 detailedAction->setActionGroup(viewGroup);
1937 treeAction->setActionGroup(viewGroup);
1938 detailedTreeAction->setActionGroup(viewGroup);
1940 KToggleAction *showHiddenAction = new KToggleAction(i18n("Show Hidden Files"), this);
1941 d->actionCollection->addAction("show hidden", showHiddenAction);
1942 connect(showHiddenAction, SIGNAL(toggled(bool)), SLOT(_k_slotToggleHidden(bool)));
1944 KToggleAction *previewAction = new KToggleAction(i18n("Show Aside Preview"), this);
1945 d->actionCollection->addAction("preview", previewAction);
1946 connect(previewAction, SIGNAL(toggled(bool)),
1947 SLOT(_k_togglePreview(bool)));
1949 KToggleAction *inlinePreview = new KToggleAction(KIcon("view-preview"),
1950 i18n("Show Preview"), this);
1951 d->actionCollection->addAction("inline preview", inlinePreview);
1952 connect(inlinePreview, SIGNAL(toggled(bool)), SLOT(_k_toggleInlinePreviews(bool)));
1954 action = new KAction(i18n("Properties"), this);
1955 d->actionCollection->addAction("properties", action);
1956 action->setIcon(KIcon("document-properties"));
1957 action->setShortcut(KShortcut(Qt::ALT + Qt::Key_Return));
1958 connect(action, SIGNAL(triggered(bool)), this, SLOT(_k_slotProperties()));
1960 // the view menu actions
1961 KActionMenu* viewMenu = new KActionMenu(i18n("&View"), this);
1962 d->actionCollection->addAction("view menu", viewMenu);
1963 viewMenu->addAction(shortAction);
1964 viewMenu->addAction(detailedAction);
1965 // Comment following lines to hide the extra two modes
1966 viewMenu->addAction(treeAction);
1967 viewMenu->addAction(detailedTreeAction);
1968 // TODO: QAbstractItemView does not offer an action collection. Provide
1969 // an interface to add a custom action collection.
1971 d->actionCollection->addAssociatedWidget(this);
1972 foreach (QAction* action, d->actionCollection->actions())
1973 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
1976 void KDirOperator::setupMenu()
1978 setupMenu(SortActions | ViewActions | FileActions);
1981 void KDirOperator::setupMenu(int whichActions)
1983 // first fill the submenus (sort and view)
1984 KActionMenu *sortMenu = static_cast<KActionMenu*>(d->actionCollection->action("sorting menu"));
1985 sortMenu->menu()->clear();
1986 sortMenu->addAction(d->actionCollection->action("by name"));
1987 sortMenu->addAction(d->actionCollection->action("by size"));
1988 sortMenu->addAction(d->actionCollection->action("by date"));
1989 sortMenu->addAction(d->actionCollection->action("by type"));
1990 sortMenu->addSeparator();
1991 sortMenu->addAction(d->actionCollection->action("descending"));
1993 // now plug everything into the popupmenu
1994 d->actionMenu->menu()->clear();
1995 if (whichActions & NavActions) {
1996 d->actionMenu->addAction(d->actionCollection->action("up"));
1997 d->actionMenu->addAction(d->actionCollection->action("back"));
1998 d->actionMenu->addAction(d->actionCollection->action("forward"));
1999 d->actionMenu->addAction(d->actionCollection->action("home"));
2000 d->actionMenu->addSeparator();
2003 if (whichActions & FileActions) {
2004 d->actionMenu->addAction(d->actionCollection->action("mkdir"));
2005 if (d->currUrl.isLocalFile() && !(QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
2006 d->actionMenu->addAction(d->actionCollection->action("trash"));
2008 KConfigGroup cg(KGlobal::config(), QLatin1String("KDE"));
2009 const bool del = !d->currUrl.isLocalFile() ||
2010 (QApplication::keyboardModifiers() & Qt::ShiftModifier) ||
2011 cg.readEntry("ShowDeleteCommand", false);
2012 if (del) {
2013 d->actionMenu->addAction(d->actionCollection->action("delete"));
2015 d->actionMenu->addSeparator();
2018 if (whichActions & SortActions) {
2019 d->actionMenu->addAction(sortMenu);
2020 if (!(whichActions & ViewActions)) {
2021 d->actionMenu->addSeparator();
2025 if (whichActions & ViewActions) {
2026 d->actionMenu->addAction(d->actionCollection->action("view menu"));
2027 d->actionMenu->addSeparator();
2030 if (whichActions & FileActions) {
2031 d->actionMenu->addAction(d->actionCollection->action("properties"));
2035 void KDirOperator::updateSortActions()
2037 if (KFile::isSortByName(d->sorting)) {
2038 d->actionCollection->action("by name")->setChecked(true);
2039 } else if (KFile::isSortByDate(d->sorting)) {
2040 d->actionCollection->action("by date")->setChecked(true);
2041 } else if (KFile::isSortBySize(d->sorting)) {
2042 d->actionCollection->action("by size")->setChecked(true);
2043 } else if (KFile::isSortByType(d->sorting)) {
2044 d->actionCollection->action("by type")->setChecked(true);
2046 d->actionCollection->action("descending")->setChecked(d->sorting & QDir::Reversed);
2049 void KDirOperator::updateViewActions()
2051 KFile::FileView fv = static_cast<KFile::FileView>(d->viewKind);
2053 //QAction *separateDirs = d->actionCollection->action("separate dirs");
2054 //separateDirs->setChecked(KFile::isSeparateDirs(fv) &&
2055 // separateDirs->isEnabled());
2057 d->actionCollection->action("short view")->setChecked(KFile::isSimpleView(fv));
2058 d->actionCollection->action("detailed view")->setChecked(KFile::isDetailView(fv));
2059 d->actionCollection->action("tree view")->setChecked(KFile::isTreeView(fv));
2060 d->actionCollection->action("detailed tree view")->setChecked(KFile::isDetailTreeView(fv));
2063 void KDirOperator::readConfig(const KConfigGroup& configGroup)
2065 d->defaultView = 0;
2066 QDir::SortFlags sorting = QDir::Name;
2068 QString viewStyle = configGroup.readEntry("View Style", "Simple");
2069 if (viewStyle == QLatin1String("Detail")) {
2070 d->defaultView |= KFile::Detail;
2071 } else if (viewStyle == QLatin1String("Tree")) {
2072 d->defaultView |= KFile::Tree;
2073 } else if (viewStyle == QLatin1String("DetailTree")) {
2074 d->defaultView |= KFile::DetailTree;
2075 } else {
2076 d->defaultView |= KFile::Simple;
2079 //if (configGroup.readEntry(QLatin1String("Separate Directories"),
2080 // DefaultMixDirsAndFiles)) {
2081 // d->defaultView |= KFile::SeparateDirs;
2083 if (configGroup.readEntry(QLatin1String("Show Preview"), false)) {
2084 d->defaultView |= KFile::PreviewContents;
2086 d->previewWidth = configGroup.readEntry(QLatin1String("Preview Width"), 100);
2088 if (configGroup.readEntry(QLatin1String("Sort directories first"),
2089 DefaultDirsFirst)) {
2090 sorting |= QDir::DirsFirst;
2093 QString name = QLatin1String("Name");
2094 QString sortBy = configGroup.readEntry(QLatin1String("Sort by"), name);
2095 if (sortBy == name) {
2096 sorting |= QDir::Name;
2097 } else if (sortBy == QLatin1String("Size")) {
2098 sorting |= QDir::Size;
2099 } else if (sortBy == QLatin1String("Date")) {
2100 sorting |= QDir::Time;
2101 } else if (sortBy == QLatin1String("Type")) {
2102 sorting |= QDir::Type;
2105 d->sorting = sorting;
2107 if (configGroup.readEntry(QLatin1String("Show hidden files"),
2108 DefaultShowHidden)) {
2109 d->actionCollection->action("show hidden")->setChecked(true);
2110 d->dirLister->setShowingDotFiles(true);
2112 const bool descending = configGroup.readEntry(QLatin1String("Sort reversed"),
2113 DefaultSortReversed);
2114 d->actionCollection->action("descending")->setChecked(descending);
2115 if (descending) {
2116 d->sorting = d->sorting | QDir::Reversed;
2119 setSorting(d->sorting);
2120 if (d->inlinePreviewState == Private::NotForced) {
2121 d->showPreviews = configGroup.readEntry(QLatin1String("Previews"), false);
2124 decorationPosition = (QStyleOptionViewItem::Position) configGroup.readEntry(QLatin1String("Decoration position"), (int) QStyleOptionViewItem::Left);
2125 const bool decorationAtLeft = decorationPosition == QStyleOptionViewItem::Left;
2126 d->actionCollection->action("decorationAtLeft")->setChecked(decorationAtLeft);
2127 d->actionCollection->action("decorationAtTop")->setChecked(!decorationAtLeft);
2130 void KDirOperator::writeConfig(KConfigGroup& configGroup)
2132 QString sortBy = QLatin1String("Name");
2133 if (KFile::isSortBySize(d->sorting)) {
2134 sortBy = QLatin1String("Size");
2135 } else if (KFile::isSortByDate(d->sorting)) {
2136 sortBy = QLatin1String("Date");
2137 } else if (KFile::isSortByType(d->sorting)) {
2138 sortBy = QLatin1String("Type");
2141 configGroup.writeEntry(QLatin1String("Sort by"), sortBy);
2143 configGroup.writeEntry(QLatin1String("Sort reversed"),
2144 d->actionCollection->action("descending")->isChecked());
2146 // don't save the preview when an application specific preview is in use.
2147 bool appSpecificPreview = false;
2148 if (d->preview) {
2149 KFileMetaPreview *tmp = dynamic_cast<KFileMetaPreview*>(d->preview);
2150 appSpecificPreview = (tmp == 0);
2153 if (!appSpecificPreview) {
2154 KToggleAction *previewAction = static_cast<KToggleAction*>(d->actionCollection->action("preview"));
2155 if (previewAction->isEnabled()) {
2156 bool hasPreview = previewAction->isChecked();
2157 configGroup.writeEntry(QLatin1String("Show Preview"), hasPreview);
2159 if (hasPreview) {
2160 // remember the width of the preview widget
2161 QList<int> sizes = d->splitter->sizes();
2162 Q_ASSERT(sizes.count() == 2);
2163 configGroup.writeEntry(QLatin1String("Preview Width"), sizes[1]);
2168 configGroup.writeEntry(QLatin1String("Show hidden files"),
2169 d->actionCollection->action("show hidden")->isChecked());
2171 KFile::FileView fv = static_cast<KFile::FileView>(d->viewKind);
2172 QString style;
2173 if (KFile::isDetailView(fv))
2174 style = QLatin1String("Detail");
2175 else if (KFile::isSimpleView(fv))
2176 style = QLatin1String("Simple");
2177 else if (KFile::isTreeView(fv))
2178 style = QLatin1String("Tree");
2179 else if (KFile::isDetailTreeView(fv))
2180 style = QLatin1String("DetailTree");
2181 configGroup.writeEntry(QLatin1String("View Style"), style);
2183 if (d->inlinePreviewState == Private::NotForced) {
2184 configGroup.writeEntry(QLatin1String("Previews"), d->showPreviews);
2187 configGroup.writeEntry(QLatin1String("Decoration position"), (int) decorationPosition);
2190 void KDirOperator::resizeEvent(QResizeEvent *)
2192 // resize the splitter and assure that the width of
2193 // the preview widget is restored
2194 QList<int> sizes = d->splitter->sizes();
2195 const bool hasPreview = (sizes.count() == 2);
2197 d->splitter->resize(size());
2198 sizes = d->splitter->sizes();
2200 const bool restorePreviewWidth = hasPreview && (d->previewWidth != sizes[1]);
2201 if (restorePreviewWidth) {
2202 const int availableWidth = sizes[0] + sizes[1];
2203 sizes[0] = availableWidth - d->previewWidth;
2204 sizes[1] = d->previewWidth;
2205 d->splitter->setSizes(sizes);
2207 if (hasPreview) {
2208 d->previewWidth = sizes[1];
2211 if (d->progressBar->parent() == this) {
2212 // might be reparented into a statusbar
2213 d->progressBar->move(2, height() - d->progressBar->height() - 2);
2217 void KDirOperator::setOnlyDoubleClickSelectsFiles(bool enable)
2219 d->onlyDoubleClickSelectsFiles = enable;
2220 // TODO: port to Qt4's QAbstractItemModel
2221 //if (d->itemView != 0) {
2222 // d->itemView->setOnlyDoubleClickSelectsFiles(enable);
2226 bool KDirOperator::onlyDoubleClickSelectsFiles() const
2228 return d->onlyDoubleClickSelectsFiles;
2231 void KDirOperator::Private::_k_slotStarted()
2233 progressBar->setValue(0);
2234 // delay showing the progressbar for one second
2235 progressDelayTimer->setSingleShot(true);
2236 progressDelayTimer->start(1000);
2239 void KDirOperator::Private::_k_slotShowProgress()
2241 progressBar->raise();
2242 progressBar->show();
2243 QApplication::flush();
2246 void KDirOperator::Private::_k_slotProgress(int percent)
2248 progressBar->setValue(percent);
2249 // we have to redraw this as fast as possible
2250 if (progressBar->isVisible())
2251 QApplication::flush();
2255 void KDirOperator::Private::_k_slotIOFinished()
2257 progressDelayTimer->stop();
2258 _k_slotProgress(100);
2259 progressBar->hide();
2260 emit parent->finishedLoading();
2261 parent->resetCursor();
2263 if (preview) {
2264 preview->clearPreview();
2268 void KDirOperator::Private::_k_slotCanceled()
2270 emit parent->finishedLoading();
2271 parent->resetCursor();
2274 QProgressBar * KDirOperator::progressBar() const
2276 return d->progressBar;
2279 void KDirOperator::clearHistory()
2281 qDeleteAll(d->backStack);
2282 d->backStack.clear();
2283 d->actionCollection->action("back")->setEnabled(false);
2285 qDeleteAll(d->forwardStack);
2286 d->forwardStack.clear();
2287 d->actionCollection->action("forward")->setEnabled(false);
2290 void KDirOperator::setEnableDirHighlighting(bool enable)
2292 d->dirHighlighting = enable;
2295 bool KDirOperator::dirHighlighting() const
2297 return d->dirHighlighting;
2300 bool KDirOperator::dirOnlyMode() const
2302 return dirOnlyMode(d->mode);
2305 bool KDirOperator::dirOnlyMode(uint mode)
2307 return ((mode & KFile::Directory) &&
2308 (mode & (KFile::File | KFile::Files)) == 0);
2311 void KDirOperator::Private::_k_slotProperties()
2313 if (itemView == 0) {
2314 return;
2317 const KFileItemList list = parent->selectedItems();
2318 if (!list.isEmpty()) {
2319 KPropertiesDialog dialog(list, parent);
2320 dialog.exec();
2324 void KDirOperator::Private::_k_slotPressed(const QModelIndex&)
2326 // Remember whether the left mouse button has been pressed, to prevent
2327 // that a right-click on an item opens an item (see _k_slotDoubleClicked() and
2328 // _k_openContextMenu()).
2329 const Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
2330 leftButtonPressed = (QApplication::mouseButtons() & Qt::LeftButton) &&
2331 !(modifiers & Qt::ShiftModifier) && !(modifiers & Qt::ControlModifier);
2334 void KDirOperator::Private::_k_slotActivated(const QModelIndex& index)
2336 const QModelIndex dirIndex = proxyModel->mapToSource(index);
2337 KFileItem item = dirModel->itemForIndex(dirIndex);
2339 const Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
2340 if (item.isNull() || (modifiers & Qt::ShiftModifier) || (modifiers & Qt::ControlModifier))
2341 return;
2343 if (item.isDir()) {
2344 parent->selectDir(item);
2345 } else if (!isSaving) {
2346 parent->selectFile(item);
2350 void KDirOperator::Private::_k_slotDoubleClicked(const QModelIndex& index)
2352 if (!leftButtonPressed) {
2353 return;
2356 const QModelIndex dirIndex = proxyModel->mapToSource(index);
2357 KFileItem item = dirModel->itemForIndex(dirIndex);
2359 if (item.isNull())
2360 return;
2362 if (item.isDir()) {
2363 parent->selectDir(item);
2364 } else {
2365 parent->selectFile(item);
2369 void KDirOperator::Private::_k_slotSelectionChanged()
2371 if (itemView == 0) {
2372 return;
2375 // In the multiselection mode each selection change is indicated by
2376 // emitting a null item. Also when the selection has been cleared, a
2377 // null item must be emitted.
2378 const bool multiSelectionMode = (itemView->selectionMode() == QAbstractItemView::ExtendedSelection);
2379 const bool hasSelection = itemView->selectionModel()->hasSelection();
2380 if (multiSelectionMode || !hasSelection) {
2381 KFileItem nullItem;
2382 parent->highlightFile(nullItem);
2384 else {
2385 KFileItem selectedItem = parent->selectedItems().first();
2386 parent->highlightFile(selectedItem);
2390 void KDirOperator::Private::_k_openContextMenu(const QPoint& pos)
2392 leftButtonPressed = false;
2394 const QModelIndex proxyIndex = itemView->indexAt(pos);
2395 const QModelIndex dirIndex = proxyModel->mapToSource(proxyIndex);
2396 KFileItem item = dirModel->itemForIndex(dirIndex);
2398 if (item.isNull())
2399 return;
2401 parent->activatedMenu(item, QCursor::pos());
2404 void KDirOperator::Private::_k_triggerPreview(const QModelIndex& index)
2406 if ((preview != 0) && index.isValid() && (index.column() == KDirModel::Name)) {
2407 const QModelIndex dirIndex = proxyModel->mapToSource(index);
2408 const KFileItem item = dirModel->itemForIndex(dirIndex);
2410 if (item.isNull())
2411 return;
2413 if (!item.isDir()) {
2414 previewUrl = item.url();
2415 _k_showPreview();
2416 } else {
2417 preview->clearPreview();
2422 void KDirOperator::Private::_k_showPreview()
2424 if (preview != 0) {
2425 preview->showPreview(previewUrl);
2429 void KDirOperator::Private::_k_slotSplitterMoved(int, int)
2431 const QList<int> sizes = splitter->sizes();
2432 if (sizes.count() == 2) {
2433 // remember the width of the preview widget (see KDirOperator::resizeEvent())
2434 previewWidth = sizes[1];
2438 void KDirOperator::Private::_k_assureVisibleSelection()
2440 if (itemView == 0) {
2441 return;
2444 QItemSelectionModel* selModel = itemView->selectionModel();
2445 if (selModel->hasSelection()) {
2446 const QModelIndex index = selModel->currentIndex();
2447 itemView->scrollTo(index, QAbstractItemView::EnsureVisible);
2448 _k_triggerPreview(index);
2453 void KDirOperator::Private::_k_synchronizeSortingState(int logicalIndex, Qt::SortOrder order)
2455 switch (logicalIndex) {
2456 case KDirModel::Name: parent->sortByName(); break;
2457 case KDirModel::Size: parent->sortBySize(); break;
2458 case KDirModel::ModifiedTime: parent->sortByDate(); break;
2459 case KDirModel::Type: parent->sortByType(); break;
2462 actionCollection->action("descending")->setChecked(order == Qt::DescendingOrder);
2464 proxyModel->sort(sortColumn(), sortOrder());
2465 QMetaObject::invokeMethod(parent, "_k_assureVisibleSelection", Qt::QueuedConnection);
2468 void KDirOperator::Private::_k_slotChangeDecorationPosition()
2470 if (!itemView) {
2471 return;
2474 QListView *view = qobject_cast<QListView*>(itemView);
2476 if (!view) {
2477 return;
2480 const bool leftChecked = actionCollection->action("decorationAtLeft")->isChecked();
2482 if (leftChecked) {
2483 decorationPosition = QStyleOptionViewItem::Left;
2484 view->setFlow(QListView::TopToBottom);
2485 } else {
2486 decorationPosition = QStyleOptionViewItem::Top;
2487 view->setFlow(QListView::LeftToRight);
2490 updateListViewGrid();
2492 itemView->update();
2495 void KDirOperator::Private::_k_slotExpandToUrl(const QModelIndex &index)
2497 QTreeView *treeView = qobject_cast<QTreeView*>(itemView);
2499 if (!treeView) {
2500 return;
2503 const KFileItem item = dirModel->itemForIndex(index);
2505 if (item.isNull()) {
2506 return;
2509 if (!item.isDir()) {
2510 const QModelIndex proxyIndex = proxyModel->mapFromSource(index);
2512 KUrl::List::Iterator it = itemsToBeSetAsCurrent.begin();
2513 while (it != itemsToBeSetAsCurrent.end()) {
2514 const KUrl url = *it;
2515 if (url.isParentOf(item.url())) {
2516 const KFileItem _item = dirLister->findByUrl(url);
2517 if (_item.isDir()) {
2518 const QModelIndex _index = dirModel->indexForItem(_item);
2519 const QModelIndex _proxyIndex = proxyModel->mapFromSource(_index);
2520 treeView->expand(_proxyIndex);
2522 // if we have expanded the last parent of this item, select it
2523 if (item.url().directory() == url.path(KUrl::RemoveTrailingSlash)) {
2524 treeView->selectionModel()->select(proxyIndex, QItemSelectionModel::Select);
2527 it = itemsToBeSetAsCurrent.erase(it);
2528 } else {
2529 ++it;
2532 } else if (!itemsToBeSetAsCurrent.contains(item.url())) {
2533 itemsToBeSetAsCurrent << item.url();
2537 void KDirOperator::Private::updateListViewGrid()
2539 if (!itemView) {
2540 return;
2543 QListView *view = qobject_cast<QListView*>(itemView);
2545 if (!view) {
2546 return;
2549 const bool leftChecked = actionCollection->action("decorationAtLeft")->isChecked();
2551 if (leftChecked) {
2552 view->setGridSize(QSize());
2553 KFileItemDelegate *delegate = qobject_cast<KFileItemDelegate*>(view->itemDelegate());
2554 if (delegate) {
2555 delegate->setMaximumSize(QSize());
2557 } else {
2558 const QFontMetrics metrics(itemView->viewport()->font());
2559 int size = itemView->iconSize().height() + metrics.height() * 2;
2560 // some heuristics for good looking. let's guess width = height * (3 / 2) is nice
2561 view->setGridSize(QSize(size * (3.0 / 2.0), size + metrics.height()));
2562 KFileItemDelegate *delegate = qobject_cast<KFileItemDelegate*>(view->itemDelegate());
2563 if (delegate) {
2564 delegate->setMaximumSize(QSize(size * (3.0 / 2.0), size + metrics.height()));
2569 int KDirOperator::Private::iconSizeForViewType(QAbstractItemView *itemView) const
2571 if (!itemView || !configGroup) {
2572 return 0;
2575 if (qobject_cast<QListView*>(itemView)) {
2576 return configGroup->readEntry("listViewIconSize", 0);
2577 } else {
2578 return configGroup->readEntry("detailedViewIconSize", 0);
2582 void KDirOperator::setViewConfig(KConfigGroup& configGroup)
2584 delete d->configGroup;
2585 d->configGroup = new KConfigGroup(configGroup);
2588 KConfigGroup* KDirOperator::viewConfigGroup() const
2590 return d->configGroup;
2593 void KDirOperator::setShowHiddenFiles(bool s)
2595 d->actionCollection->action("show hidden")->setChecked(s);
2598 bool KDirOperator::showHiddenFiles() const
2600 return d->actionCollection->action("show hidden")->isChecked();
2603 // ### temporary code
2604 #include <dirent.h>
2605 bool KDirOperator::Private::isReadable(const KUrl& url)
2607 if (!url.isLocalFile())
2608 return true; // what else can we say?
2610 KDE_struct_stat buf;
2611 #ifdef Q_WS_WIN
2612 QString ts = url.toLocalFile();
2613 #else
2614 QString ts = url.path(KUrl::AddTrailingSlash);
2615 #endif
2616 bool readable = (KDE::stat(ts, &buf) == 0);
2617 if (readable) { // further checks
2618 DIR *test;
2619 test = opendir(QFile::encodeName(ts)); // we do it just to test here
2620 readable = (test != 0);
2621 if (test)
2622 closedir(test);
2624 return readable;
2627 #include "kdiroperator.moc"