]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinview.cpp
reset the information panel if an item is shown that got deleted
[dolphin.git] / src / dolphinview.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at> *
3 * Copyright (C) 2006 by Gregor Kališnik <gregor@podnapisi.net> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program 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 *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include "dolphinview.h"
22
23 #include <QApplication>
24 #include <QClipboard>
25 #include <QKeyEvent>
26 #include <QItemSelection>
27 #include <QBoxLayout>
28 #include <QTimer>
29 #include <QScrollBar>
30
31 #include <kactioncollection.h>
32 #include <kcolorscheme.h>
33 #include <kdirlister.h>
34 #include <kfilepreviewgenerator.h>
35 #include <kiconeffect.h>
36 #include <kfileitem.h>
37 #include <klocale.h>
38 #include <kio/deletejob.h>
39 #include <kio/netaccess.h>
40 #include <kio/previewjob.h>
41 #include <kjob.h>
42 #include <kmenu.h>
43 #include <kmessagebox.h>
44 #include <kmimetyperesolver.h>
45 #include <konq_fileitemcapabilities.h>
46 #include <konq_operations.h>
47 #include <konqmimedata.h>
48 #include <kstringhandler.h>
49 #include <ktoggleaction.h>
50 #include <kurl.h>
51
52 #include "dolphinmodel.h"
53 #include "dolphincolumnview.h"
54 #include "dolphincontroller.h"
55 #include "dolphinfileitemdelegate.h"
56 #include "dolphinsortfilterproxymodel.h"
57 #include "dolphindetailsview.h"
58 #include "dolphin_detailsmodesettings.h"
59 #include "dolphiniconsview.h"
60 #include "settings/dolphinsettings.h"
61 #include "dolphin_generalsettings.h"
62 #include "draganddrophelper.h"
63 #include "folderexpander.h"
64 #include "renamedialog.h"
65 #include "tooltips/tooltipmanager.h"
66 #include "viewproperties.h"
67 #include "zoomlevelinfo.h"
68
69 /**
70 * Helper function for sorting items with qSort() in
71 * DolphinView::renameSelectedItems().
72 */
73 bool lessThan(const KFileItem& item1, const KFileItem& item2)
74 {
75 return KStringHandler::naturalCompare(item1.name(), item2.name()) < 0;
76 }
77
78 DolphinView::DolphinView(QWidget* parent,
79 const KUrl& url,
80 KDirLister* dirLister,
81 DolphinModel* dolphinModel,
82 DolphinSortFilterProxyModel* proxyModel) :
83 QWidget(parent),
84 m_active(true),
85 m_showPreview(false),
86 m_loadingDirectory(false),
87 m_storedCategorizedSorting(false),
88 m_tabsForFiles(false),
89 m_isContextMenuOpen(false),
90 m_ignoreViewProperties(false),
91 m_assureVisibleCurrentIndex(false),
92 m_mode(DolphinView::IconsView),
93 m_topLayout(0),
94 m_controller(0),
95 m_iconsView(0),
96 m_detailsView(0),
97 m_columnView(0),
98 m_fileItemDelegate(0),
99 m_selectionModel(0),
100 m_dolphinModel(dolphinModel),
101 m_dirLister(dirLister),
102 m_proxyModel(proxyModel),
103 m_previewGenerator(0),
104 m_toolTipManager(0),
105 m_rootUrl(),
106 m_currentItemUrl(),
107 m_expandedDragSource(0)
108 {
109 m_topLayout = new QVBoxLayout(this);
110 m_topLayout->setSpacing(0);
111 m_topLayout->setMargin(0);
112
113 m_controller = new DolphinController(this);
114 m_controller->setUrl(url);
115
116 connect(m_controller, SIGNAL(urlChanged(const KUrl&)),
117 this, SIGNAL(urlChanged(const KUrl&)));
118 connect(m_controller, SIGNAL(requestUrlChange(const KUrl&)),
119 this, SLOT(slotRequestUrlChange(const KUrl&)));
120
121 connect(m_controller, SIGNAL(requestContextMenu(const QPoint&, const QList<QAction*>&)),
122 this, SLOT(openContextMenu(const QPoint&, const QList<QAction*>&)));
123 connect(m_controller, SIGNAL(urlsDropped(const KFileItem&, const KUrl&, QDropEvent*)),
124 this, SLOT(dropUrls(const KFileItem&, const KUrl&, QDropEvent*)));
125 connect(m_controller, SIGNAL(sortingChanged(DolphinView::Sorting)),
126 this, SLOT(updateSorting(DolphinView::Sorting)));
127 connect(m_controller, SIGNAL(sortOrderChanged(Qt::SortOrder)),
128 this, SLOT(updateSortOrder(Qt::SortOrder)));
129 connect(m_controller, SIGNAL(additionalInfoChanged(const KFileItemDelegate::InformationList&)),
130 this, SLOT(updateAdditionalInfo(const KFileItemDelegate::InformationList&)));
131 connect(m_controller, SIGNAL(itemTriggered(const KFileItem&)),
132 this, SLOT(triggerItem(const KFileItem&)));
133 connect(m_controller, SIGNAL(tabRequested(const KUrl&)),
134 this, SIGNAL(tabRequested(const KUrl&)));
135 connect(m_controller, SIGNAL(activated()),
136 this, SLOT(activate()));
137 connect(m_controller, SIGNAL(itemEntered(const KFileItem&)),
138 this, SLOT(showHoverInformation(const KFileItem&)));
139 connect(m_controller, SIGNAL(viewportEntered()),
140 this, SLOT(clearHoverInformation()));
141
142 connect(m_dirLister, SIGNAL(redirection(KUrl, KUrl)),
143 this, SIGNAL(redirection(KUrl, KUrl)));
144 connect(m_dirLister, SIGNAL(completed()),
145 this, SLOT(restoreCurrentItem()));
146 connect(m_dirLister, SIGNAL(refreshItems(const QList<QPair<KFileItem,KFileItem>>&)),
147 this, SLOT(slotRefreshItems()));
148
149 applyViewProperties(url);
150 m_topLayout->addWidget(itemView());
151 }
152
153 DolphinView::~DolphinView()
154 {
155 delete m_expandedDragSource;
156 m_expandedDragSource = 0;
157 }
158
159 const KUrl& DolphinView::url() const
160 {
161 return m_controller->url();
162 }
163
164 KUrl DolphinView::rootUrl() const
165 {
166 return isColumnViewActive() ? m_columnView->rootUrl() : url();
167 }
168
169 void DolphinView::setActive(bool active)
170 {
171 if (active == m_active) {
172 return;
173 }
174
175 m_active = active;
176
177 QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
178 if (active) {
179 // TODO: emitting urlChanged() is a hack, as the URL hasn't really changed. It
180 // bypasses the problem when having a split view and changing the active view to
181 // update the some URL dependent states. A nicer approach should be no big deal...
182 emit urlChanged(url());
183 emit selectionChanged(selectedItems());
184 } else {
185 color.setAlpha(150);
186 }
187
188 QWidget* viewport = itemView()->viewport();
189 QPalette palette;
190 palette.setColor(viewport->backgroundRole(), color);
191 viewport->setPalette(palette);
192
193 update();
194
195 if (active) {
196 itemView()->setFocus();
197 emit activated();
198 }
199
200 m_controller->indicateActivationChange(active);
201 }
202
203 bool DolphinView::isActive() const
204 {
205 return m_active;
206 }
207
208 void DolphinView::setMode(Mode mode)
209 {
210 if (mode == m_mode) {
211 return; // the wished mode is already set
212 }
213
214 const int oldZoomLevel = m_controller->zoomLevel();
215 m_mode = mode;
216
217 deleteView();
218
219 const KUrl viewPropsUrl = viewPropertiesUrl();
220 ViewProperties props(viewPropsUrl);
221 props.setViewMode(m_mode);
222 createView();
223
224 // the file item delegate has been recreated, apply the current
225 // additional information manually
226 const KFileItemDelegate::InformationList infoList = props.additionalInfo();
227 m_fileItemDelegate->setShowInformation(infoList);
228 emit additionalInfoChanged();
229
230 // Not all view modes support categorized sorting. Adjust the sorting model
231 // if changing the view mode results in a change of the categorized sorting
232 // capabilities.
233 m_storedCategorizedSorting = props.categorizedSorting();
234 const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting();
235 if (categorized != m_proxyModel->isCategorizedModel()) {
236 m_proxyModel->setCategorizedModel(categorized);
237 emit categorizedSortingChanged();
238 }
239
240 emit modeChanged();
241
242 updateZoomLevel(oldZoomLevel);
243 if (m_showPreview) {
244 loadDirectory(viewPropsUrl);
245 }
246 }
247
248 DolphinView::Mode DolphinView::mode() const
249 {
250 return m_mode;
251 }
252
253 bool DolphinView::showPreview() const
254 {
255 return m_showPreview;
256 }
257
258 bool DolphinView::showHiddenFiles() const
259 {
260 return m_dirLister->showingDotFiles();
261 }
262
263 bool DolphinView::categorizedSorting() const
264 {
265 // If all view modes would support categorized sorting, returning
266 // m_proxyModel->isCategorizedModel() would be the way to go. As
267 // currently only the icons view supports caterized sorting, we remember
268 // the stored view properties state in m_storedCategorizedSorting and
269 // return this state. The application takes care to disable the corresponding
270 // checkbox by checking DolphinView::supportsCategorizedSorting() to indicate
271 // that this setting is not applied to the current view mode.
272 return m_storedCategorizedSorting;
273 }
274
275 bool DolphinView::supportsCategorizedSorting() const
276 {
277 return m_iconsView != 0;
278 }
279
280 void DolphinView::selectAll()
281 {
282 QAbstractItemView* view = itemView();
283 // TODO: there seems to be a bug in QAbstractItemView::selectAll(); if
284 // the Ctrl-key is pressed (e. g. for Ctrl+A), selectAll() inverts the
285 // selection instead of selecting all items. This is bypassed for KDE 4.0
286 // by invoking clearSelection() first.
287 view->clearSelection();
288 view->selectAll();
289 }
290
291 void DolphinView::invertSelection()
292 {
293 if (isColumnViewActive()) {
294 // QAbstractItemView does not offer a virtual method invertSelection()
295 // as counterpart to QAbstractItemView::selectAll(). This makes it
296 // necessary to delegate the inverting of the selection to the
297 // column view, as only the selection of the active column should
298 // get inverted.
299 m_columnView->invertSelection();
300 } else {
301 QItemSelectionModel* selectionModel = itemView()->selectionModel();
302 const QAbstractItemModel* itemModel = selectionModel->model();
303
304 const QModelIndex topLeft = itemModel->index(0, 0);
305 const QModelIndex bottomRight = itemModel->index(itemModel->rowCount() - 1,
306 itemModel->columnCount() - 1);
307
308 const QItemSelection selection(topLeft, bottomRight);
309 selectionModel->select(selection, QItemSelectionModel::Toggle);
310 }
311 }
312
313 bool DolphinView::hasSelection() const
314 {
315 return itemView()->selectionModel()->hasSelection();
316 }
317
318 void DolphinView::clearSelection()
319 {
320 QItemSelectionModel* selModel = itemView()->selectionModel();
321 const QModelIndex currentIndex = selModel->currentIndex();
322 selModel->setCurrentIndex(currentIndex, QItemSelectionModel::Current |
323 QItemSelectionModel::Clear);
324 }
325
326 KFileItemList DolphinView::selectedItems() const
327 {
328 if (isColumnViewActive()) {
329 return m_columnView->selectedItems();
330 }
331
332 const QAbstractItemView* view = itemView();
333
334 // Our view has a selection, we will map them back to the DolphinModel
335 // and then fill the KFileItemList.
336 Q_ASSERT((view != 0) && (view->selectionModel() != 0));
337
338 const QItemSelection selection = m_proxyModel->mapSelectionToSource(view->selectionModel()->selection());
339 KFileItemList itemList;
340
341 const QModelIndexList indexList = selection.indexes();
342 foreach (const QModelIndex &index, indexList) {
343 KFileItem item = m_dolphinModel->itemForIndex(index);
344 if (!item.isNull()) {
345 itemList.append(item);
346 }
347 }
348
349 return itemList;
350 }
351
352 KUrl::List DolphinView::selectedUrls() const
353 {
354 KUrl::List urls;
355 const KFileItemList list = selectedItems();
356 foreach (const KFileItem &item, list) {
357 urls.append(item.url());
358 }
359 return urls;
360 }
361
362 int DolphinView::selectedItemsCount() const
363 {
364 if (isColumnViewActive()) {
365 // TODO: get rid of this special case by adjusting the dir lister
366 // to the current column
367 return m_columnView->selectedItems().count();
368 }
369
370 return itemView()->selectionModel()->selection().count();
371 }
372
373 void DolphinView::setContentsPosition(int x, int y)
374 {
375 QAbstractItemView* view = itemView();
376
377 // the ColumnView takes care itself for the horizontal scrolling
378 if (!isColumnViewActive()) {
379 view->horizontalScrollBar()->setValue(x);
380 }
381 view->verticalScrollBar()->setValue(y);
382
383 m_loadingDirectory = false;
384 }
385
386 QPoint DolphinView::contentsPosition() const
387 {
388 const int x = itemView()->horizontalScrollBar()->value();
389 const int y = itemView()->verticalScrollBar()->value();
390 return QPoint(x, y);
391 }
392
393 void DolphinView::setZoomLevel(int level)
394 {
395 if (level < ZoomLevelInfo::minimumLevel()) {
396 level = ZoomLevelInfo::minimumLevel();
397 } else if (level > ZoomLevelInfo::maximumLevel()) {
398 level = ZoomLevelInfo::maximumLevel();
399 }
400
401 if (level != zoomLevel()) {
402 m_controller->setZoomLevel(level);
403 m_previewGenerator->updatePreviews();
404 emit zoomLevelChanged(level);
405 }
406 }
407
408 int DolphinView::zoomLevel() const
409 {
410 return m_controller->zoomLevel();
411 }
412
413 void DolphinView::setSorting(Sorting sorting)
414 {
415 if (sorting != this->sorting()) {
416 updateSorting(sorting);
417 }
418 }
419
420 DolphinView::Sorting DolphinView::sorting() const
421 {
422 return m_proxyModel->sorting();
423 }
424
425 void DolphinView::setSortOrder(Qt::SortOrder order)
426 {
427 if (sortOrder() != order) {
428 updateSortOrder(order);
429 }
430 }
431
432 Qt::SortOrder DolphinView::sortOrder() const
433 {
434 return m_proxyModel->sortOrder();
435 }
436
437 void DolphinView::setAdditionalInfo(KFileItemDelegate::InformationList info)
438 {
439 const KUrl viewPropsUrl = viewPropertiesUrl();
440 ViewProperties props(viewPropsUrl);
441 props.setAdditionalInfo(info);
442 m_fileItemDelegate->setShowInformation(info);
443
444 emit additionalInfoChanged();
445
446 if (itemView() != m_detailsView) {
447 // the details view requires no reloading of the directory, as it maps
448 // the file item delegate info to its columns internally
449 loadDirectory(viewPropsUrl);
450 }
451 }
452
453 KFileItemDelegate::InformationList DolphinView::additionalInfo() const
454 {
455 return m_fileItemDelegate->showInformation();
456 }
457
458 void DolphinView::reload()
459 {
460 setUrl(url());
461 loadDirectory(url(), true);
462 }
463
464 void DolphinView::refresh()
465 {
466 m_ignoreViewProperties = false;
467
468 const bool oldActivationState = m_active;
469 const int oldZoomLevel = m_controller->zoomLevel();
470 m_active = true;
471
472 createView();
473 applyViewProperties(m_controller->url());
474 reload();
475
476 setActive(oldActivationState);
477 updateZoomLevel(oldZoomLevel);
478 }
479
480 void DolphinView::updateView(const KUrl& url, const KUrl& rootUrl)
481 {
482 if (m_controller->url() == url) {
483 return;
484 }
485
486 m_previewGenerator->cancelPreviews();
487 m_controller->setUrl(url); // emits urlChanged, which we forward
488
489 if (!rootUrl.isEmpty() && rootUrl.isParentOf(url)) {
490 applyViewProperties(rootUrl);
491 loadDirectory(rootUrl);
492 if (itemView() == m_columnView) {
493 m_columnView->setRootUrl(rootUrl);
494 m_columnView->showColumn(url);
495 }
496 } else {
497 applyViewProperties(url);
498 loadDirectory(url);
499 }
500
501 emit startedPathLoading(url);
502 }
503
504 void DolphinView::setNameFilter(const QString& nameFilter)
505 {
506 m_proxyModel->setFilterRegExp(nameFilter);
507
508 if (isColumnViewActive()) {
509 // adjusting the directory lister is not enough in the case of the
510 // column view, as each column has its own directory lister internally...
511 m_columnView->setNameFilter(nameFilter);
512 }
513 }
514
515 void DolphinView::calculateItemCount(int& fileCount,
516 int& folderCount,
517 KIO::filesize_t& totalFileSize) const
518 {
519 foreach (const KFileItem& item, m_dirLister->items()) {
520 if (item.isDir()) {
521 ++folderCount;
522 } else {
523 ++fileCount;
524 totalFileSize += item.size();
525 }
526 }
527 }
528
529 QString DolphinView::statusBarText() const
530 {
531 QString text;
532 int folderCount = 0;
533 int fileCount = 0;
534 KIO::filesize_t totalFileSize = 0;
535
536 if (hasSelection()) {
537 // give a summary of the status of the selected files
538 const KFileItemList list = selectedItems();
539 if (list.isEmpty()) {
540 // when an item is triggered, it is temporary selected but selectedItems()
541 // will return an empty list
542 return text;
543 }
544
545 KFileItemList::const_iterator it = list.begin();
546 const KFileItemList::const_iterator end = list.end();
547 while (it != end) {
548 const KFileItem& item = *it;
549 if (item.isDir()) {
550 ++folderCount;
551 } else {
552 ++fileCount;
553 totalFileSize += item.size();
554 }
555 ++it;
556 }
557
558 if (folderCount + fileCount == 1) {
559 // if only one item is selected, show the filename
560 const QString name = list.first().name();
561 text = (folderCount == 1) ? i18nc("@info:status", "<filename>%1</filename> selected", name) :
562 i18nc("@info:status", "<filename>%1</filename> selected (%2)",
563 name, KIO::convertSize(totalFileSize));
564 } else {
565 // at least 2 items are selected
566 const QString foldersText = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount);
567 const QString filesText = i18ncp("@info:status", "1 File selected", "%1 Files selected", fileCount);
568 if ((folderCount > 0) && (fileCount > 0)) {
569 text = i18nc("@info:status folders, files (size)", "%1, %2 (%3)",
570 foldersText, filesText, KIO::convertSize(totalFileSize));
571 } else if (fileCount > 0) {
572 text = i18nc("@info:status files (size)", "%1 (%2)", filesText, KIO::convertSize(totalFileSize));
573 } else {
574 Q_ASSERT(folderCount > 0);
575 text = foldersText;
576 }
577 }
578 } else {
579 calculateItemCount(fileCount, folderCount, totalFileSize);
580 text = KIO::itemsSummaryString(fileCount + folderCount,
581 fileCount, folderCount,
582 totalFileSize, true);
583 }
584
585 return text;
586 }
587
588 void DolphinView::setUrl(const KUrl& url)
589 {
590 // remember current item candidate (see restoreCurrentItem())
591 m_currentItemUrl = url;
592 updateView(url, KUrl());
593 }
594
595 void DolphinView::changeSelection(const KFileItemList& selection)
596 {
597 clearSelection();
598 if (selection.isEmpty()) {
599 return;
600 }
601 const KUrl& baseUrl = url();
602 KUrl url;
603 QItemSelection new_selection;
604 foreach(const KFileItem& item, selection) {
605 url = item.url().upUrl();
606 if (baseUrl.equals(url, KUrl::CompareWithoutTrailingSlash)) {
607 QModelIndex index = m_proxyModel->mapFromSource(m_dolphinModel->indexForItem(item));
608 new_selection.select(index, index);
609 }
610 }
611 itemView()->selectionModel()->select(new_selection,
612 QItemSelectionModel::ClearAndSelect
613 | QItemSelectionModel::Current);
614 }
615
616 void DolphinView::renameSelectedItems()
617 {
618 KFileItemList items = selectedItems();
619 const int itemCount = items.count();
620 if (itemCount < 1) {
621 return;
622 }
623
624 if (itemCount > 1) {
625 // More than one item has been selected for renaming. Open
626 // a rename dialog and rename all items afterwards.
627 RenameDialog dialog(this, items);
628 if (dialog.exec() == QDialog::Rejected) {
629 return;
630 }
631
632 const QString newName = dialog.newName();
633 if (newName.isEmpty()) {
634 emit errorMessage(dialog.errorString());
635 return;
636 }
637
638 // TODO: check how this can be integrated into KIO::FileUndoManager/KonqOperations
639 // as one operation instead of n rename operations like it is done now...
640 Q_ASSERT(newName.contains('#'));
641
642 // currently the items are sorted by the selection order, resort
643 // them by the file name
644 qSort(items.begin(), items.end(), lessThan);
645
646 // iterate through all selected items and rename them...
647 int index = 1;
648 foreach (const KFileItem& item, items) {
649 const KUrl& oldUrl = item.url();
650 QString number;
651 number.setNum(index++);
652
653 QString name = newName;
654 name.replace('#', number);
655
656 if (oldUrl.fileName() != name) {
657 KUrl newUrl = oldUrl;
658 newUrl.setFileName(name);
659 KonqOperations::rename(this, oldUrl, newUrl);
660 }
661 }
662 } else if (DolphinSettings::instance().generalSettings()->renameInline()) {
663 Q_ASSERT(itemCount == 1);
664
665 if (isColumnViewActive()) {
666 m_columnView->editItem(items.first());
667 } else {
668 const QModelIndex dirIndex = m_dolphinModel->indexForItem(items.first());
669 const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
670 itemView()->edit(proxyIndex);
671 }
672 } else {
673 Q_ASSERT(itemCount == 1);
674
675 RenameDialog dialog(this, items);
676 if (dialog.exec() == QDialog::Rejected) {
677 return;
678 }
679
680 const QString& newName = dialog.newName();
681 if (newName.isEmpty()) {
682 emit errorMessage(dialog.errorString());
683 return;
684 }
685
686 const KUrl& oldUrl = items.first().url();
687 KUrl newUrl = oldUrl;
688 newUrl.setFileName(newName);
689 KonqOperations::rename(this, oldUrl, newUrl);
690 }
691
692 // assure that the current index remains visible when KDirLister
693 // will notify the view about changed items
694 m_assureVisibleCurrentIndex = true;
695 }
696
697 void DolphinView::trashSelectedItems()
698 {
699 const KUrl::List list = simplifiedSelectedUrls();
700 KonqOperations::del(this, KonqOperations::TRASH, list);
701 }
702
703 void DolphinView::deleteSelectedItems()
704 {
705 const KUrl::List list = simplifiedSelectedUrls();
706 const bool del = KonqOperations::askDeleteConfirmation(list,
707 KonqOperations::DEL,
708 KonqOperations::DEFAULT_CONFIRMATION,
709 this);
710
711 if (del) {
712 KIO::Job* job = KIO::del(list);
713 connect(job, SIGNAL(result(KJob*)),
714 this, SLOT(slotDeleteFileFinished(KJob*)));
715 }
716 }
717
718 void DolphinView::cutSelectedItems()
719 {
720 QMimeData* mimeData = selectionMimeData();
721 KonqMimeData::addIsCutSelection(mimeData, true);
722 QApplication::clipboard()->setMimeData(mimeData);
723 }
724
725 void DolphinView::copySelectedItems()
726 {
727 QMimeData* mimeData = selectionMimeData();
728 QApplication::clipboard()->setMimeData(mimeData);
729 }
730
731 void DolphinView::paste()
732 {
733 pasteToUrl(url());
734 }
735
736 void DolphinView::pasteIntoFolder()
737 {
738 const KFileItemList items = selectedItems();
739 if ((items.count() == 1) && items.first().isDir()) {
740 pasteToUrl(items.first().url());
741 }
742 }
743
744 void DolphinView::setShowPreview(bool show)
745 {
746 if (m_showPreview == show) {
747 return;
748 }
749
750 const KUrl viewPropsUrl = viewPropertiesUrl();
751 ViewProperties props(viewPropsUrl);
752 props.setShowPreview(show);
753
754 m_showPreview = show;
755 m_previewGenerator->setPreviewShown(show);
756
757 const int oldZoomLevel = m_controller->zoomLevel();
758 emit showPreviewChanged();
759
760 // Enabling or disabling the preview might change the icon size of the view.
761 // As the view does not emit a signal when the icon size has been changed,
762 // the used zoom level of the controller must be adjusted manually:
763 updateZoomLevel(oldZoomLevel);
764
765 loadDirectory(viewPropsUrl);
766 }
767
768 void DolphinView::setShowHiddenFiles(bool show)
769 {
770 if (m_dirLister->showingDotFiles() == show) {
771 return;
772 }
773
774 const KUrl viewPropsUrl = viewPropertiesUrl();
775 ViewProperties props(viewPropsUrl);
776 props.setShowHiddenFiles(show);
777
778 m_dirLister->setShowingDotFiles(show);
779 emit showHiddenFilesChanged();
780
781 loadDirectory(viewPropsUrl);
782 }
783
784 void DolphinView::setCategorizedSorting(bool categorized)
785 {
786 if (categorized == categorizedSorting()) {
787 return;
788 }
789
790 // setCategorizedSorting(true) may only get invoked
791 // if the view supports categorized sorting
792 Q_ASSERT(!categorized || supportsCategorizedSorting());
793
794 ViewProperties props(viewPropertiesUrl());
795 props.setCategorizedSorting(categorized);
796 props.save();
797
798 m_storedCategorizedSorting = categorized;
799 m_proxyModel->setCategorizedModel(categorized);
800
801 emit categorizedSortingChanged();
802 }
803
804 void DolphinView::toggleSortOrder()
805 {
806 const Qt::SortOrder order = (sortOrder() == Qt::AscendingOrder) ?
807 Qt::DescendingOrder :
808 Qt::AscendingOrder;
809 setSortOrder(order);
810 }
811
812 void DolphinView::toggleAdditionalInfo(QAction* action)
813 {
814 const KFileItemDelegate::Information info =
815 static_cast<KFileItemDelegate::Information>(action->data().toInt());
816
817 KFileItemDelegate::InformationList list = additionalInfo();
818
819 const bool show = action->isChecked();
820
821 const int index = list.indexOf(info);
822 const bool containsInfo = (index >= 0);
823 if (show && !containsInfo) {
824 list.append(info);
825 setAdditionalInfo(list);
826 } else if (!show && containsInfo) {
827 list.removeAt(index);
828 setAdditionalInfo(list);
829 Q_ASSERT(list.indexOf(info) < 0);
830 }
831 }
832
833 void DolphinView::mouseReleaseEvent(QMouseEvent* event)
834 {
835 QWidget::mouseReleaseEvent(event);
836 setActive(true);
837 }
838
839 void DolphinView::wheelEvent(QWheelEvent* event)
840 {
841 if (event->modifiers() & Qt::ControlModifier) {
842 const int delta = event->delta();
843 const int level = zoomLevel();
844 if (delta > 0) {
845 setZoomLevel(level + 1);
846 } else if (delta < 0) {
847 setZoomLevel(level - 1);
848 }
849 event->accept();
850 }
851 }
852
853 bool DolphinView::eventFilter(QObject* watched, QEvent* event)
854 {
855 switch (event->type()) {
856 case QEvent::FocusIn:
857 if (watched == itemView()) {
858 m_controller->requestActivation();
859 }
860 break;
861
862 case QEvent::MouseButtonPress:
863 if ((watched == itemView()->viewport()) && (m_expandedDragSource != 0)) {
864 // Listening to a mousebutton press event to delete expanded views is a
865 // workaround, as it seems impossible for the FolderExpander to know when
866 // a dragging outside a view has been finished. However it works quite well:
867 // A mousebutton press event indicates that a drag operation must be
868 // finished already.
869 m_expandedDragSource->deleteLater();
870 m_expandedDragSource = 0;
871 }
872 break;
873
874 case QEvent::DragEnter:
875 if (watched == itemView()->viewport()) {
876 setActive(true);
877 }
878 break;
879
880 case QEvent::KeyPress:
881 if (watched == itemView()) {
882 if (m_toolTipManager != 0) {
883 m_toolTipManager->hideTip();
884 }
885
886 // clear the selection when Escape has been pressed
887 QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
888 if (keyEvent->key() == Qt::Key_Escape) {
889 clearSelection();
890 }
891 }
892 break;
893
894 default:
895 break;
896 }
897
898 return QWidget::eventFilter(watched, event);
899 }
900
901 void DolphinView::activate()
902 {
903 setActive(true);
904 }
905
906 void DolphinView::triggerItem(const KFileItem& item)
907 {
908 const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
909 if ((modifier & Qt::ShiftModifier) || (modifier & Qt::ControlModifier)) {
910 // items are selected by the user, hence don't trigger the
911 // item specified by 'index'
912 return;
913 }
914
915 // TODO: the m_isContextMenuOpen check is a workaround for Qt-issue 207192
916 if (item.isNull() || m_isContextMenuOpen) {
917 return;
918 }
919
920 if (m_toolTipManager != 0) {
921 m_toolTipManager->hideTip();
922 }
923 emit itemTriggered(item); // caught by DolphinViewContainer or DolphinPart
924 }
925
926 void DolphinView::emitSelectionChangedSignal()
927 {
928 emit selectionChanged(DolphinView::selectedItems());
929 }
930
931 void DolphinView::openContextMenu(const QPoint& pos,
932 const QList<QAction*>& customActions)
933 {
934 KFileItem item;
935 if (isColumnViewActive()) {
936 item = m_columnView->itemAt(pos);
937 } else {
938 const QModelIndex index = itemView()->indexAt(pos);
939 if (index.isValid() && (index.column() == DolphinModel::Name)) {
940 const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
941 item = m_dolphinModel->itemForIndex(dolphinModelIndex);
942 }
943 }
944
945 if (m_toolTipManager != 0) {
946 m_toolTipManager->hideTip();
947 }
948
949 m_isContextMenuOpen = true; // TODO: workaround for Qt-issue 207192
950 emit requestContextMenu(item, url(), customActions);
951 m_isContextMenuOpen = false;
952 }
953
954 void DolphinView::dropUrls(const KFileItem& destItem,
955 const KUrl& destPath,
956 QDropEvent* event)
957 {
958 DragAndDropHelper::instance().dropUrls(destItem, destPath, event, this);
959 }
960
961 void DolphinView::updateSorting(DolphinView::Sorting sorting)
962 {
963 ViewProperties props(viewPropertiesUrl());
964 props.setSorting(sorting);
965
966 m_proxyModel->setSorting(sorting);
967
968 emit sortingChanged(sorting);
969 }
970
971 void DolphinView::updateSortOrder(Qt::SortOrder order)
972 {
973 ViewProperties props(viewPropertiesUrl());
974 props.setSortOrder(order);
975
976 m_proxyModel->setSortOrder(order);
977
978 emit sortOrderChanged(order);
979 }
980
981 void DolphinView::updateAdditionalInfo(const KFileItemDelegate::InformationList& info)
982 {
983 ViewProperties props(viewPropertiesUrl());
984 props.setAdditionalInfo(info);
985 props.save();
986
987 m_fileItemDelegate->setShowInformation(info);
988
989 emit additionalInfoChanged();
990 }
991
992 void DolphinView::updateAdditionalInfoActions(KActionCollection* collection)
993 {
994 const bool enable = (m_mode == DolphinView::DetailsView) ||
995 (m_mode == DolphinView::IconsView);
996
997 QAction* showSizeInfo = collection->action("show_size_info");
998 QAction* showDateInfo = collection->action("show_date_info");
999 QAction* showPermissionsInfo = collection->action("show_permissions_info");
1000 QAction* showOwnerInfo = collection->action("show_owner_info");
1001 QAction* showGroupInfo = collection->action("show_group_info");
1002 QAction* showMimeInfo = collection->action("show_mime_info");
1003
1004 showSizeInfo->setChecked(false);
1005 showDateInfo->setChecked(false);
1006 showPermissionsInfo->setChecked(false);
1007 showOwnerInfo->setChecked(false);
1008 showGroupInfo->setChecked(false);
1009 showMimeInfo->setChecked(false);
1010
1011 showSizeInfo->setEnabled(enable);
1012 showDateInfo->setEnabled(enable);
1013 showPermissionsInfo->setEnabled(enable);
1014 showOwnerInfo->setEnabled(enable);
1015 showGroupInfo->setEnabled(enable);
1016 showMimeInfo->setEnabled(enable);
1017
1018 foreach (KFileItemDelegate::Information info, m_fileItemDelegate->showInformation()) {
1019 switch (info) {
1020 case KFileItemDelegate::Size:
1021 showSizeInfo->setChecked(true);
1022 break;
1023 case KFileItemDelegate::ModificationTime:
1024 showDateInfo->setChecked(true);
1025 break;
1026 case KFileItemDelegate::Permissions:
1027 showPermissionsInfo->setChecked(true);
1028 break;
1029 case KFileItemDelegate::Owner:
1030 showOwnerInfo->setChecked(true);
1031 break;
1032 case KFileItemDelegate::OwnerAndGroup:
1033 showGroupInfo->setChecked(true);
1034 break;
1035 case KFileItemDelegate::FriendlyMimeType:
1036 showMimeInfo->setChecked(true);
1037 break;
1038 default:
1039 break;
1040 }
1041 }
1042 }
1043
1044 QPair<bool, QString> DolphinView::pasteInfo() const
1045 {
1046 return KonqOperations::pasteInfo(url());
1047 }
1048
1049 void DolphinView::setTabsForFilesEnabled(bool tabsForFiles)
1050 {
1051 m_tabsForFiles = tabsForFiles;
1052 }
1053
1054 bool DolphinView::isTabsForFilesEnabled() const
1055 {
1056 return m_tabsForFiles;
1057 }
1058
1059 bool DolphinView::itemsExpandable() const
1060 {
1061 return (m_detailsView != 0) && m_detailsView->itemsExpandable();
1062 }
1063
1064 void DolphinView::deleteWhenNotDragSource(QAbstractItemView *view)
1065 {
1066 if (view == 0)
1067 return;
1068
1069 if (DragAndDropHelper::instance().isDragSource(view)) {
1070 // We must store for later deletion.
1071 if (m_expandedDragSource != 0) {
1072 // The old stored view is obviously not the drag source anymore.
1073 m_expandedDragSource->deleteLater();
1074 m_expandedDragSource = 0;
1075 }
1076 view->hide();
1077 m_expandedDragSource = view;
1078 }
1079 else {
1080 view->deleteLater();
1081 }
1082 }
1083
1084 void DolphinView::emitContentsMoved()
1085 {
1086 // only emit the contents moved signal if:
1087 // - no directory loading is ongoing (this would reset the contents position
1088 // always to (0, 0))
1089 // - if the Column View is active: the column view does an automatic
1090 // positioning during the loading operation, which must be remembered
1091 if (!m_loadingDirectory || isColumnViewActive()) {
1092 const QPoint pos(contentsPosition());
1093 emit contentsMoved(pos.x(), pos.y());
1094 }
1095 }
1096
1097 void DolphinView::showHoverInformation(const KFileItem& item)
1098 {
1099 emit requestItemInfo(item);
1100 }
1101
1102 void DolphinView::clearHoverInformation()
1103 {
1104 emit requestItemInfo(KFileItem());
1105 }
1106
1107 void DolphinView::slotDeleteFileFinished(KJob* job)
1108 {
1109 if (job->error() == 0) {
1110 emit operationCompletedMessage(i18nc("@info:status", "Delete operation completed."));
1111 } else if (job->error() != KIO::ERR_USER_CANCELED) {
1112 emit errorMessage(job->errorString());
1113 }
1114 }
1115
1116 void DolphinView::slotRequestUrlChange(const KUrl& url)
1117 {
1118 emit requestUrlChange(url);
1119 m_controller->setUrl(url);
1120 }
1121
1122 void DolphinView::restoreCurrentItem()
1123 {
1124 const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_currentItemUrl);
1125 if (dirIndex.isValid()) {
1126 const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
1127 QAbstractItemView* view = itemView();
1128 const bool clearSelection = !hasSelection();
1129 view->setCurrentIndex(proxyIndex);
1130 if (clearSelection) {
1131 view->clearSelection();
1132 }
1133 }
1134 }
1135
1136 void DolphinView::slotRefreshItems()
1137 {
1138 if (m_assureVisibleCurrentIndex) {
1139 m_assureVisibleCurrentIndex = false;
1140 itemView()->scrollTo(itemView()->currentIndex());
1141 }
1142 }
1143
1144 void DolphinView::loadDirectory(const KUrl& url, bool reload)
1145 {
1146 if (!url.isValid()) {
1147 const QString location(url.pathOrUrl());
1148 if (location.isEmpty()) {
1149 emit errorMessage(i18nc("@info:status", "The location is empty."));
1150 } else {
1151 emit errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location));
1152 }
1153 return;
1154 }
1155
1156 m_loadingDirectory = true;
1157
1158 m_dirLister->stop();
1159 m_dirLister->openUrl(url, reload ? KDirLister::Reload : KDirLister::NoFlags);
1160
1161 if (isColumnViewActive()) {
1162 // adjusting the directory lister is not enough in the case of the
1163 // column view, as each column has its own directory lister internally...
1164 if (reload) {
1165 m_columnView->reload();
1166 } else {
1167 m_columnView->showColumn(url);
1168 }
1169 }
1170 }
1171
1172 KUrl DolphinView::viewPropertiesUrl() const
1173 {
1174 if (isColumnViewActive()) {
1175 return m_columnView->rootUrl();
1176 }
1177
1178 return url();
1179 }
1180
1181 void DolphinView::applyViewProperties(const KUrl& url)
1182 {
1183 if (m_ignoreViewProperties) {
1184 return;
1185 }
1186
1187 if (isColumnViewActive() && rootUrl().isParentOf(url)) {
1188 // The column view is active, hence don't apply the view properties
1189 // of sub directories (represented by columns) to the view. The
1190 // view always represents the properties of the first column.
1191 return;
1192 }
1193
1194 const ViewProperties props(url);
1195
1196 const Mode mode = props.viewMode();
1197 if (m_mode != mode) {
1198 const int oldZoomLevel = m_controller->zoomLevel();
1199
1200 m_mode = mode;
1201 createView();
1202 emit modeChanged();
1203
1204 updateZoomLevel(oldZoomLevel);
1205 }
1206 if (itemView() == 0) {
1207 createView();
1208 }
1209 Q_ASSERT(itemView() != 0);
1210 Q_ASSERT(m_fileItemDelegate != 0);
1211
1212 const bool showHiddenFiles = props.showHiddenFiles();
1213 if (showHiddenFiles != m_dirLister->showingDotFiles()) {
1214 m_dirLister->setShowingDotFiles(showHiddenFiles);
1215 emit showHiddenFilesChanged();
1216 }
1217
1218 m_storedCategorizedSorting = props.categorizedSorting();
1219 const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting();
1220 if (categorized != m_proxyModel->isCategorizedModel()) {
1221 m_proxyModel->setCategorizedModel(categorized);
1222 emit categorizedSortingChanged();
1223 }
1224
1225 const DolphinView::Sorting sorting = props.sorting();
1226 if (sorting != m_proxyModel->sorting()) {
1227 m_proxyModel->setSorting(sorting);
1228 emit sortingChanged(sorting);
1229 }
1230
1231 const Qt::SortOrder sortOrder = props.sortOrder();
1232 if (sortOrder != m_proxyModel->sortOrder()) {
1233 m_proxyModel->setSortOrder(sortOrder);
1234 emit sortOrderChanged(sortOrder);
1235 }
1236
1237 KFileItemDelegate::InformationList info = props.additionalInfo();
1238 if (info != m_fileItemDelegate->showInformation()) {
1239 m_fileItemDelegate->setShowInformation(info);
1240 emit additionalInfoChanged();
1241 }
1242
1243 const bool showPreview = props.showPreview();
1244 if (showPreview != m_showPreview) {
1245 m_showPreview = showPreview;
1246 m_previewGenerator->setPreviewShown(showPreview);
1247
1248 const int oldZoomLevel = m_controller->zoomLevel();
1249 emit showPreviewChanged();
1250
1251 // Enabling or disabling the preview might change the icon size of the view.
1252 // As the view does not emit a signal when the icon size has been changed,
1253 // the used zoom level of the controller must be adjusted manually:
1254 updateZoomLevel(oldZoomLevel);
1255 }
1256
1257 if (DolphinSettings::instance().generalSettings()->globalViewProps()) {
1258 // During the lifetime of a DolphinView instance the global view properties
1259 // should not be changed. This allows e. g. to split a view and use different
1260 // view properties for each view.
1261 m_ignoreViewProperties = true;
1262 }
1263 }
1264
1265 void DolphinView::createView()
1266 {
1267 deleteView();
1268 Q_ASSERT(m_iconsView == 0);
1269 Q_ASSERT(m_detailsView == 0);
1270 Q_ASSERT(m_columnView == 0);
1271
1272 QAbstractItemView* view = 0;
1273 switch (m_mode) {
1274 case IconsView: {
1275 m_iconsView = new DolphinIconsView(this, m_controller);
1276 view = m_iconsView;
1277 break;
1278 }
1279
1280 case DetailsView:
1281 m_detailsView = new DolphinDetailsView(this, m_controller);
1282 view = m_detailsView;
1283 break;
1284
1285 case ColumnView:
1286 m_columnView = new DolphinColumnView(this, m_controller);
1287 view = m_columnView;
1288 break;
1289 }
1290
1291 Q_ASSERT(view != 0);
1292 view->installEventFilter(this);
1293 view->viewport()->installEventFilter(this);
1294 setFocusProxy(view);
1295
1296 if (m_mode != ColumnView) {
1297 // Give the view the ability to auto-expand its directories on hovering
1298 // (the column view takes care about this itself). If the details view
1299 // uses expandable folders, the auto-expanding should be used always.
1300 DolphinSettings& settings = DolphinSettings::instance();
1301 const bool enabled = settings.generalSettings()->autoExpandFolders() ||
1302 ((m_detailsView != 0) && settings.detailsModeSettings()->expandableFolders());
1303
1304 FolderExpander* folderExpander = new FolderExpander(view, m_proxyModel);
1305 folderExpander->setEnabled(enabled);
1306 connect(folderExpander, SIGNAL(enterDir(const QModelIndex&)),
1307 m_controller, SLOT(triggerItem(const QModelIndex&)));
1308 }
1309 else {
1310 // Listen out for requests to delete the current column.
1311 connect(m_columnView, SIGNAL(requestColumnDeletion(QAbstractItemView*)),
1312 this, SLOT(deleteWhenNotDragSource(QAbstractItemView*)));
1313 }
1314
1315 m_controller->setItemView(view);
1316
1317 m_fileItemDelegate = new DolphinFileItemDelegate(view);
1318 m_fileItemDelegate->setShowToolTipWhenElided(false);
1319 m_fileItemDelegate->setMinimizedNameColumn(m_mode == DetailsView);
1320 view->setItemDelegate(m_fileItemDelegate);
1321
1322 view->setModel(m_proxyModel);
1323 if (m_selectionModel != 0) {
1324 view->setSelectionModel(m_selectionModel);
1325 } else {
1326 m_selectionModel = view->selectionModel();
1327 }
1328
1329 // reparent the selection model, as it should not be deleted
1330 // when deleting the model
1331 m_selectionModel->setParent(this);
1332
1333 view->setSelectionMode(QAbstractItemView::ExtendedSelection);
1334
1335 m_previewGenerator = new KFilePreviewGenerator(view);
1336 m_previewGenerator->setPreviewShown(m_showPreview);
1337
1338 if (DolphinSettings::instance().generalSettings()->showToolTips()) {
1339 m_toolTipManager = new ToolTipManager(view, m_proxyModel);
1340 connect(m_controller, SIGNAL(hideToolTip()),
1341 m_toolTipManager, SLOT(hideTip()));
1342 }
1343
1344 m_topLayout->insertWidget(1, view);
1345
1346 connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
1347 this, SLOT(emitSelectionChangedSignal()));
1348 connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
1349 this, SLOT(emitContentsMoved()));
1350 connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)),
1351 this, SLOT(emitContentsMoved()));
1352 }
1353
1354 void DolphinView::deleteView()
1355 {
1356 QAbstractItemView* view = itemView();
1357 if (view != 0) {
1358 // It's important to set the keyboard focus to the parent
1359 // before deleting the view: Otherwise when having a split
1360 // view the other view will get the focus and will request
1361 // an activation (see DolphinView::eventFilter()).
1362 setFocusProxy(0);
1363 setFocus();
1364
1365 m_topLayout->removeWidget(view);
1366 view->close();
1367
1368 // m_previewGenerator's parent is not always destroyed, and we
1369 // don't want two active at once - manually delete.
1370 delete m_previewGenerator;
1371 m_previewGenerator = 0;
1372
1373 disconnect(view);
1374 m_controller->disconnect(view);
1375 view->disconnect();
1376
1377 deleteWhenNotDragSource(view);
1378 view = 0;
1379
1380 m_iconsView = 0;
1381 m_detailsView = 0;
1382 m_columnView = 0;
1383 m_fileItemDelegate = 0;
1384 m_toolTipManager = 0;
1385 }
1386 }
1387
1388 QAbstractItemView* DolphinView::itemView() const
1389 {
1390 if (m_detailsView != 0) {
1391 return m_detailsView;
1392 } else if (m_columnView != 0) {
1393 return m_columnView;
1394 }
1395
1396 return m_iconsView;
1397 }
1398
1399 bool DolphinView::isCutItem(const KFileItem& item) const
1400 {
1401 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
1402 const KUrl::List cutUrls = KUrl::List::fromMimeData(mimeData);
1403
1404 const KUrl& itemUrl = item.url();
1405 KUrl::List::const_iterator it = cutUrls.begin();
1406 const KUrl::List::const_iterator end = cutUrls.end();
1407 while (it != end) {
1408 if (*it == itemUrl) {
1409 return true;
1410 }
1411 ++it;
1412 }
1413
1414 return false;
1415 }
1416
1417 void DolphinView::pasteToUrl(const KUrl& url)
1418 {
1419 KonqOperations::doPaste(this, url);
1420 }
1421
1422 void DolphinView::updateZoomLevel(int oldZoomLevel)
1423 {
1424 const int newZoomLevel = ZoomLevelInfo::zoomLevelForIconSize(itemView()->iconSize());
1425 if (oldZoomLevel != newZoomLevel) {
1426 m_controller->setZoomLevel(newZoomLevel);
1427 emit zoomLevelChanged(newZoomLevel);
1428 }
1429 }
1430
1431 KUrl::List DolphinView::simplifiedSelectedUrls() const
1432 {
1433 KUrl::List list = selectedUrls();
1434 if (itemsExpandable() ) {
1435 list = KDirModel::simplifiedUrlList(list);
1436 }
1437 return list;
1438 }
1439
1440 QMimeData* DolphinView::selectionMimeData() const
1441 {
1442 if (isColumnViewActive()) {
1443 return m_columnView->selectionMimeData();
1444 }
1445
1446 const QAbstractItemView* view = itemView();
1447 Q_ASSERT((view != 0) && (view->selectionModel() != 0));
1448 const QItemSelection selection = m_proxyModel->mapSelectionToSource(view->selectionModel()->selection());
1449 return m_dolphinModel->mimeData(selection.indexes());
1450 }
1451
1452 #include "dolphinview.moc"