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