]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinview.cpp
Extracted the servicemenu code from KonqPopupMenu into KonqMenuActions, and used...
[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 <kcolorscheme.h>
32 #include <kdirlister.h>
33 #include <kfileitemdelegate.h>
34 #include <klocale.h>
35 #include <kiconeffect.h>
36 #include <kio/netaccess.h>
37 #include <kio/renamedialog.h>
38 #include <kio/previewjob.h>
39 #include <kmimetyperesolver.h>
40 #include <konqmimedata.h>
41 #include <konq_operations.h>
42 #include <kurl.h>
43
44 #include "dolphinmodel.h"
45 #include "dolphincolumnview.h"
46 #include "dolphincontroller.h"
47 #include "dolphinsortfilterproxymodel.h"
48 #include "dolphindetailsview.h"
49 #include "dolphiniconsview.h"
50 #include "renamedialog.h"
51 #include "viewproperties.h"
52 #include "dolphinsettings.h"
53 #include "dolphin_generalsettings.h"
54
55 DolphinView::DolphinView(QWidget* parent,
56 const KUrl& url,
57 KDirLister* dirLister,
58 DolphinModel* dolphinModel,
59 DolphinSortFilterProxyModel* proxyModel) :
60 QWidget(parent),
61 m_active(true),
62 m_loadingDirectory(false),
63 m_storedCategorizedSorting(false),
64 m_mode(DolphinView::IconsView),
65 m_topLayout(0),
66 m_controller(0),
67 m_iconsView(0),
68 m_detailsView(0),
69 m_columnView(0),
70 m_fileItemDelegate(0),
71 m_dolphinModel(dolphinModel),
72 m_dirLister(dirLister),
73 m_proxyModel(proxyModel)
74 {
75 setFocusPolicy(Qt::StrongFocus);
76 m_topLayout = new QVBoxLayout(this);
77 m_topLayout->setSpacing(0);
78 m_topLayout->setMargin(0);
79
80 QClipboard* clipboard = QApplication::clipboard();
81 connect(clipboard, SIGNAL(dataChanged()),
82 this, SLOT(updateCutItems()));
83
84 connect(m_dirLister, SIGNAL(completed()),
85 this, SLOT(updateCutItems()));
86 connect(m_dirLister, SIGNAL(newItems(const KFileItemList&)),
87 this, SLOT(generatePreviews(const KFileItemList&)));
88
89 m_controller = new DolphinController(this);
90 m_controller->setUrl(url);
91 connect(m_controller, SIGNAL(urlChanged(const KUrl&)),
92 this, SIGNAL(urlChanged(const KUrl&)));
93 connect(m_controller, SIGNAL(requestContextMenu(const QPoint&)),
94 this, SLOT(openContextMenu(const QPoint&)));
95 connect(m_controller, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&, const QModelIndex&, QWidget*)),
96 this, SLOT(dropUrls(const KUrl::List&, const KUrl&, const QModelIndex&, QWidget*)));
97 connect(m_controller, SIGNAL(sortingChanged(DolphinView::Sorting)),
98 this, SLOT(updateSorting(DolphinView::Sorting)));
99 connect(m_controller, SIGNAL(sortOrderChanged(Qt::SortOrder)),
100 this, SLOT(updateSortOrder(Qt::SortOrder)));
101 connect(m_controller, SIGNAL(itemTriggered(const KFileItem&)),
102 this, SLOT(triggerItem(const KFileItem&)));
103 connect(m_controller, SIGNAL(activated()),
104 this, SLOT(activate()));
105 connect(m_controller, SIGNAL(itemEntered(const KFileItem&)),
106 this, SLOT(showHoverInformation(const KFileItem&)));
107 connect(m_controller, SIGNAL(viewportEntered()),
108 this, SLOT(clearHoverInformation()));
109
110 applyViewProperties(url);
111 m_topLayout->addWidget(itemView());
112 }
113
114 DolphinView::~DolphinView()
115 {
116 }
117
118 const KUrl& DolphinView::url() const
119 {
120 return m_controller->url();
121 }
122
123 KUrl DolphinView::rootUrl() const
124 {
125 return isColumnViewActive() ? m_columnView->rootUrl() : url();
126 }
127
128 void DolphinView::setActive(bool active)
129 {
130 if (active == m_active) {
131 return;
132 }
133
134 m_active = active;
135
136 QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
137 if (active) {
138 // TODO: emitting urlChanged() is a hack, as the URL hasn't really changed. It
139 // bypasses the problem when having a split view and changing the active view to
140 // update the some URL dependent states. A nicer approach should be no big deal...
141 emit urlChanged(url());
142 emit selectionChanged(selectedItems());
143 } else {
144 color.setAlpha(150);
145 }
146
147 QWidget* viewport = itemView()->viewport();
148 QPalette palette;
149 palette.setColor(viewport->backgroundRole(), color);
150 viewport->setPalette(palette);
151
152 update();
153
154 if (active) {
155 emit activated();
156 }
157
158 m_controller->indicateActivationChange(active);
159 }
160
161 bool DolphinView::isActive() const
162 {
163 return m_active;
164 }
165
166 void DolphinView::setMode(Mode mode)
167 {
168 if (mode == m_mode) {
169 return; // the wished mode is already set
170 }
171
172 m_mode = mode;
173
174 if (isColumnViewActive()) {
175 // When changing the mode in the column view, it makes sense
176 // to go back to the root URL of the column view automatically.
177 // Otherwise there it would not be possible to turn off the column view
178 // without focusing the first column.
179 const KUrl root = rootUrl();
180 setUrl(root);
181 m_controller->setUrl(root);
182 }
183
184 const KUrl viewPropsUrl = viewPropertiesUrl();
185 ViewProperties props(viewPropsUrl);
186 props.setViewMode(m_mode);
187
188 createView();
189
190 // Not all view modes support categorized sorting. Adjust the sorting model
191 // if changing the view mode results in a change of the categorized sorting
192 // capabilities.
193 m_storedCategorizedSorting = props.categorizedSorting();
194 const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting();
195 if (categorized != m_proxyModel->isCategorizedModel()) {
196 m_proxyModel->setCategorizedModel(categorized);
197 m_proxyModel->sort(m_proxyModel->sortColumn(), m_proxyModel->sortOrder());
198 emit categorizedSortingChanged();
199 }
200
201 loadDirectory(viewPropsUrl);
202
203 emit modeChanged();
204 }
205
206 DolphinView::Mode DolphinView::mode() const
207 {
208 return m_mode;
209 }
210
211 void DolphinView::setShowPreview(bool show)
212 {
213 const KUrl viewPropsUrl = viewPropertiesUrl();
214 ViewProperties props(viewPropsUrl);
215 props.setShowPreview(show);
216
217 m_controller->setShowPreview(show);
218 emit showPreviewChanged();
219
220 loadDirectory(viewPropsUrl, true);
221 }
222
223 bool DolphinView::showPreview() const
224 {
225 return m_controller->showPreview();
226 }
227
228 void DolphinView::setShowHiddenFiles(bool show)
229 {
230 if (m_dirLister->showingDotFiles() == show) {
231 return;
232 }
233
234 const KUrl viewPropsUrl = viewPropertiesUrl();
235 ViewProperties props(viewPropsUrl);
236 props.setShowHiddenFiles(show);
237
238 m_dirLister->setShowingDotFiles(show);
239 m_controller->setShowHiddenFiles(show);
240 emit showHiddenFilesChanged();
241
242 loadDirectory(viewPropsUrl, true);
243 }
244
245 bool DolphinView::showHiddenFiles() const
246 {
247 return m_dirLister->showingDotFiles();
248 }
249
250 void DolphinView::setCategorizedSorting(bool categorized)
251 {
252 if (categorized == categorizedSorting()) {
253 return;
254 }
255
256 // setCategorizedSorting(true) may only get invoked
257 // if the view supports categorized sorting
258 Q_ASSERT(!categorized || supportsCategorizedSorting());
259
260 ViewProperties props(viewPropertiesUrl());
261 props.setCategorizedSorting(categorized);
262 props.save();
263
264 m_storedCategorizedSorting = categorized;
265 m_proxyModel->setCategorizedModel(categorized);
266 m_proxyModel->sort(m_proxyModel->sortColumn(), m_proxyModel->sortOrder());
267
268 emit categorizedSortingChanged();
269 }
270
271 bool DolphinView::categorizedSorting() const
272 {
273 // If all view modes would support categorized sorting, returning
274 // m_proxyModel->isCategorizedModel() would be the way to go. As
275 // currently only the icons view supports caterized sorting, we remember
276 // the stored view properties state in m_storedCategorizedSorting and
277 // return this state. The application takes care to disable the corresponding
278 // checkbox by checking DolphinView::supportsCategorizedSorting() to indicate
279 // that this setting is not applied to the current view mode.
280 return m_storedCategorizedSorting;
281 }
282
283 bool DolphinView::supportsCategorizedSorting() const
284 {
285 return m_iconsView != 0;
286 }
287
288 void DolphinView::selectAll()
289 {
290 itemView()->selectAll();
291 }
292
293 void DolphinView::invertSelection()
294 {
295 if (isColumnViewActive()) {
296 // QAbstractItemView does not offer a virtual method invertSelection()
297 // as counterpart to QAbstractItemView::selectAll(). This makes it
298 // necessary to delegate the inverting of the selection to the
299 // column view, as only the selection of the active column should
300 // get inverted.
301 m_columnView->invertSelection();
302 } else {
303 QItemSelectionModel* selectionModel = itemView()->selectionModel();
304 const QAbstractItemModel* itemModel = selectionModel->model();
305
306 const QModelIndex topLeft = itemModel->index(0, 0);
307 const QModelIndex bottomRight = itemModel->index(itemModel->rowCount() - 1,
308 itemModel->columnCount() - 1);
309
310 const QItemSelection selection(topLeft, bottomRight);
311 selectionModel->select(selection, QItemSelectionModel::Toggle);
312 }
313 }
314
315 bool DolphinView::hasSelection() const
316 {
317 return itemView()->selectionModel()->hasSelection();
318 }
319
320 void DolphinView::clearSelection()
321 {
322 itemView()->selectionModel()->clear();
323 }
324
325 KFileItemList DolphinView::selectedItems() const
326 {
327 const QAbstractItemView* view = itemView();
328
329 // Our view has a selection, we will map them back to the DolphinModel
330 // and then fill the KFileItemList.
331 Q_ASSERT((view != 0) && (view->selectionModel() != 0));
332
333 const QItemSelection selection = m_proxyModel->mapSelectionToSource(view->selectionModel()->selection());
334 KFileItemList itemList;
335
336 const QModelIndexList indexList = selection.indexes();
337 foreach (QModelIndex index, indexList) {
338 KFileItem item = m_dolphinModel->itemForIndex(index);
339 if (!item.isNull()) {
340 itemList.append(item);
341 }
342 }
343
344 return itemList;
345 }
346
347 KUrl::List DolphinView::selectedUrls() const
348 {
349 KUrl::List urls;
350 const KFileItemList list = selectedItems();
351 foreach (KFileItem item, list) {
352 urls.append(item.url());
353 }
354 return urls;
355 }
356
357 KFileItem DolphinView::fileItem(const QModelIndex& index) const
358 {
359 const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
360 return m_dolphinModel->itemForIndex(dolphinModelIndex);
361 }
362
363 void DolphinView::setContentsPosition(int x, int y)
364 {
365 QAbstractItemView* view = itemView();
366
367 // the ColumnView takes care itself for the horizontal scrolling
368 if (!isColumnViewActive()) {
369 view->horizontalScrollBar()->setValue(x);
370 }
371 view->verticalScrollBar()->setValue(y);
372
373 m_loadingDirectory = false;
374 }
375
376 QPoint DolphinView::contentsPosition() const
377 {
378 const int x = itemView()->horizontalScrollBar()->value();
379 const int y = itemView()->verticalScrollBar()->value();
380 return QPoint(x, y);
381 }
382
383 void DolphinView::zoomIn()
384 {
385 m_controller->triggerZoomIn();
386 }
387
388 void DolphinView::zoomOut()
389 {
390 m_controller->triggerZoomOut();
391 }
392
393 bool DolphinView::isZoomInPossible() const
394 {
395 return m_controller->isZoomInPossible();
396 }
397
398 bool DolphinView::isZoomOutPossible() const
399 {
400 return m_controller->isZoomOutPossible();
401 }
402
403 void DolphinView::setSorting(Sorting sorting)
404 {
405 if (sorting != this->sorting()) {
406 updateSorting(sorting);
407 }
408 }
409
410 DolphinView::Sorting DolphinView::sorting() const
411 {
412 return m_proxyModel->sorting();
413 }
414
415 void DolphinView::setSortOrder(Qt::SortOrder order)
416 {
417 if (sortOrder() != order) {
418 updateSortOrder(order);
419 }
420 }
421
422 Qt::SortOrder DolphinView::sortOrder() const
423 {
424 return m_proxyModel->sortOrder();
425 }
426
427 void DolphinView::setAdditionalInfo(KFileItemDelegate::InformationList info)
428 {
429 const KUrl viewPropsUrl = viewPropertiesUrl();
430 ViewProperties props(viewPropsUrl);
431 props.setAdditionalInfo(info);
432
433 m_controller->setAdditionalInfoCount(info.count());
434 m_fileItemDelegate->setShowInformation(info);
435
436 emit additionalInfoChanged(info);
437 loadDirectory(viewPropsUrl, true);
438 }
439
440 KFileItemDelegate::InformationList DolphinView::additionalInfo() const
441 {
442 return m_fileItemDelegate->showInformation();
443 }
444
445 void DolphinView::reload()
446 {
447 setUrl(url());
448 loadDirectory(url(), true);
449 }
450
451 void DolphinView::refresh()
452 {
453 const bool oldActivationState = m_active;
454 m_active = true;
455
456 createView();
457 applyViewProperties(m_controller->url());
458 reload();
459
460 setActive(oldActivationState);
461 }
462
463 void DolphinView::updateView(const KUrl& url, const KUrl& rootUrl)
464 {
465 if (m_controller->url() == url) {
466 return;
467 }
468
469 const bool restoreColumnView = !rootUrl.isEmpty()
470 && !rootUrl.equals(url, KUrl::CompareWithoutTrailingSlash)
471 && rootUrl.isParentOf(url);
472
473 m_controller->setUrl(url); // emits urlChanged, which we forward
474
475 if (restoreColumnView) {
476 applyViewProperties(rootUrl);
477 loadDirectory(rootUrl);
478 // Restoring the column view relies on the URL-history. It might be possible
479 // that the view properties have been changed or deleted in the meantime, so
480 // it cannot be asserted that really a column view has been created:
481 if (itemView() == m_columnView) {
482 m_columnView->setRootUrl(rootUrl);
483 m_columnView->showColumn(url);
484 }
485 } else {
486 applyViewProperties(url);
487 loadDirectory(url);
488 }
489
490 itemView()->setFocus();
491
492 emit startedPathLoading(url);
493 }
494
495 void DolphinView::setUrl(const KUrl& url)
496 {
497 updateView(url, KUrl());
498 }
499
500 void DolphinView::mouseReleaseEvent(QMouseEvent* event)
501 {
502 QWidget::mouseReleaseEvent(event);
503 setActive(true);
504 }
505 void DolphinView::activate()
506 {
507 setActive(true);
508 }
509
510 void DolphinView::triggerItem(const KFileItem& item)
511 {
512 const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
513 if ((modifier & Qt::ShiftModifier) || (modifier & Qt::ControlModifier)) {
514 // items are selected by the user, hence don't trigger the
515 // item specified by 'index'
516 return;
517 }
518
519 if (item.isNull()) {
520 return;
521 }
522
523 emit itemTriggered(item); // caught by DolphinViewContainer or DolphinPart
524 }
525
526 void DolphinView::generatePreviews(const KFileItemList& items)
527 {
528 if (m_controller->showPreview()) {
529 KIO::PreviewJob* job = KIO::filePreview(items, 128);
530 connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)),
531 this, SLOT(showPreview(const KFileItem&, const QPixmap&)));
532 }
533 }
534
535 void DolphinView::showPreview(const KFileItem& item, const QPixmap& pixmap)
536 {
537 Q_ASSERT(!item.isNull());
538 if (item.url().directory() != m_dirLister->url().path()) {
539 // the preview job is still working on items of an older URL, hence
540 // the item is not part of the directory model anymore
541 return;
542 }
543
544 const QModelIndex idx = m_dolphinModel->indexForItem(item);
545 if (idx.isValid() && (idx.column() == 0)) {
546 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
547 if (KonqMimeData::decodeIsCutSelection(mimeData) && isCutItem(item)) {
548 KIconEffect iconEffect;
549 const QPixmap cutPixmap = iconEffect.apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
550 m_dolphinModel->setData(idx, QIcon(cutPixmap), Qt::DecorationRole);
551 } else {
552 m_dolphinModel->setData(idx, QIcon(pixmap), Qt::DecorationRole);
553 }
554 }
555 }
556
557 void DolphinView::emitSelectionChangedSignal()
558 {
559 emit selectionChanged(DolphinView::selectedItems());
560 }
561
562 void DolphinView::loadDirectory(const KUrl& url, bool reload)
563 {
564 if (!url.isValid()) {
565 const QString location(url.pathOrUrl());
566 if (location.isEmpty()) {
567 emit errorMessage(i18nc("@info:status", "The location is empty."));
568 } else {
569 emit errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location));
570 }
571 return;
572 }
573
574 m_cutItemsCache.clear();
575 m_loadingDirectory = true;
576
577 m_dirLister->stop();
578 m_dirLister->openUrl(url, reload ? KDirLister::Reload : KDirLister::NoFlags);
579
580 if (isColumnViewActive()) {
581 // adjusting the directory lister is not enough in the case of the
582 // column view, as each column has its own directory lister internally...
583 if (reload) {
584 m_columnView->reload();
585 } else {
586 m_columnView->showColumn(url);
587 }
588 }
589 }
590
591 KUrl DolphinView::viewPropertiesUrl() const
592 {
593 if (isColumnViewActive()) {
594 return m_dirLister->url();
595 }
596
597 return url();
598 }
599
600 void DolphinView::applyViewProperties(const KUrl& url)
601 {
602 if (isColumnViewActive() && rootUrl().isParentOf(url)) {
603 // The column view is active, hence don't apply the view properties
604 // of sub directories (represented by columns) to the view. The
605 // view always represents the properties of the first column.
606 return;
607 }
608
609 const ViewProperties props(url);
610
611 const Mode mode = props.viewMode();
612 if (m_mode != mode) {
613 m_mode = mode;
614 createView();
615 emit modeChanged();
616 }
617 if (itemView() == 0) {
618 createView();
619 }
620 Q_ASSERT(itemView() != 0);
621 Q_ASSERT(m_fileItemDelegate != 0);
622
623 const bool showHiddenFiles = props.showHiddenFiles();
624 if (showHiddenFiles != m_dirLister->showingDotFiles()) {
625 m_dirLister->setShowingDotFiles(showHiddenFiles);
626 m_controller->setShowHiddenFiles(showHiddenFiles);
627 emit showHiddenFilesChanged();
628 }
629
630 m_storedCategorizedSorting = props.categorizedSorting();
631 const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting();
632 if (categorized != m_proxyModel->isCategorizedModel()) {
633 m_proxyModel->setCategorizedModel(categorized);
634 m_proxyModel->sort(m_proxyModel->sortColumn(), m_proxyModel->sortOrder());
635 emit categorizedSortingChanged();
636 }
637
638 const DolphinView::Sorting sorting = props.sorting();
639 if (sorting != m_proxyModel->sorting()) {
640 m_proxyModel->setSorting(sorting);
641 emit sortingChanged(sorting);
642 }
643
644 const Qt::SortOrder sortOrder = props.sortOrder();
645 if (sortOrder != m_proxyModel->sortOrder()) {
646 m_proxyModel->setSortOrder(sortOrder);
647 emit sortOrderChanged(sortOrder);
648 }
649
650 KFileItemDelegate::InformationList info = props.additionalInfo();
651 if (info != m_fileItemDelegate->showInformation()) {
652 m_controller->setAdditionalInfoCount(info.count());
653 m_fileItemDelegate->setShowInformation(info);
654 emit additionalInfoChanged(info);
655 }
656
657 const bool showPreview = props.showPreview();
658 if (showPreview != m_controller->showPreview()) {
659 m_controller->setShowPreview(showPreview);
660 emit showPreviewChanged();
661 }
662 }
663
664 void DolphinView::changeSelection(const KFileItemList& selection)
665 {
666 clearSelection();
667 if (selection.isEmpty()) {
668 return;
669 }
670 const KUrl& baseUrl = url();
671 KUrl url;
672 QItemSelection new_selection;
673 foreach(const KFileItem& item, selection) {
674 url = item.url().upUrl();
675 if (baseUrl.equals(url, KUrl::CompareWithoutTrailingSlash)) {
676 QModelIndex index = m_proxyModel->mapFromSource(m_dolphinModel->indexForItem(item));
677 new_selection.select(index, index);
678 }
679 }
680 itemView()->selectionModel()->select(new_selection,
681 QItemSelectionModel::ClearAndSelect
682 | QItemSelectionModel::Current);
683 }
684
685 void DolphinView::openContextMenu(const QPoint& pos)
686 {
687 KFileItem item;
688
689 const QModelIndex index = itemView()->indexAt(pos);
690 if (isValidNameIndex(index)) {
691 item = fileItem(index);
692 }
693
694 emit requestContextMenu(item, url());
695 }
696
697 void DolphinView::dropUrls(const KUrl::List& urls,
698 const KUrl& destPath,
699 const QModelIndex& destIndex,
700 QWidget* source)
701 {
702 KFileItem directory;
703 if (isValidNameIndex(destIndex)) {
704 KFileItem item = fileItem(destIndex);
705 Q_ASSERT(!item.isNull());
706 if (item.isDir()) {
707 // the URLs are dropped above a directory
708 directory = item;
709 }
710 }
711
712 if ((directory.isNull()) && (source == itemView())) {
713 // The dropping is done into the same viewport where
714 // the dragging has been started. Just ignore this...
715 return;
716 }
717
718 const KUrl& destination = (directory.isNull()) ?
719 destPath : directory.url();
720 dropUrls(urls, destination);
721 }
722
723 void DolphinView::dropUrls(const KUrl::List& urls,
724 const KUrl& destination)
725 {
726 emit urlsDropped(urls, destination);
727 }
728
729 void DolphinView::updateSorting(DolphinView::Sorting sorting)
730 {
731 ViewProperties props(viewPropertiesUrl());
732 props.setSorting(sorting);
733
734 m_proxyModel->setSorting(sorting);
735
736 emit sortingChanged(sorting);
737 }
738
739 void DolphinView::updateSortOrder(Qt::SortOrder order)
740 {
741 ViewProperties props(viewPropertiesUrl());
742 props.setSortOrder(order);
743
744 m_proxyModel->setSortOrder(order);
745
746 emit sortOrderChanged(order);
747 }
748
749 void DolphinView::emitContentsMoved()
750 {
751 // only emit the contents moved signal if:
752 // - no directory loading is ongoing (this would reset the contents position
753 // always to (0, 0))
754 // - if the Column View is active: the column view does an automatic
755 // positioning during the loading operation, which must be remembered
756 if (!m_loadingDirectory || isColumnViewActive()) {
757 const QPoint pos(contentsPosition());
758 emit contentsMoved(pos.x(), pos.y());
759 }
760 }
761
762 void DolphinView::updateCutItems()
763 {
764 // restore the icons of all previously selected items to the
765 // original state...
766 QList<CutItem>::const_iterator it = m_cutItemsCache.begin();
767 QList<CutItem>::const_iterator end = m_cutItemsCache.end();
768 while (it != end) {
769 const QModelIndex index = m_dolphinModel->indexForUrl((*it).url);
770 if (index.isValid()) {
771 m_dolphinModel->setData(index, QIcon((*it).pixmap), Qt::DecorationRole);
772 }
773 ++it;
774 }
775 m_cutItemsCache.clear();
776
777 // ... and apply an item effect to all currently cut items
778 applyCutItemEffect();
779 }
780
781 void DolphinView::showHoverInformation(const KFileItem& item)
782 {
783 if (hasSelection()) {
784 return;
785 }
786
787 emit requestItemInfo(item);
788 }
789
790 void DolphinView::clearHoverInformation()
791 {
792 emit requestItemInfo(KFileItem());
793 }
794
795
796 void DolphinView::createView()
797 {
798 KFileItemDelegate::InformationList infoList;
799 if (m_fileItemDelegate != 0) {
800 infoList = m_fileItemDelegate->showInformation();
801 }
802
803 // delete current view
804 QAbstractItemView* view = itemView();
805 if (view != 0) {
806 m_topLayout->removeWidget(view);
807 view->close();
808 view->deleteLater();
809 view = 0;
810 m_iconsView = 0;
811 m_detailsView = 0;
812 m_columnView = 0;
813 m_fileItemDelegate = 0;
814 }
815
816 Q_ASSERT(m_iconsView == 0);
817 Q_ASSERT(m_detailsView == 0);
818 Q_ASSERT(m_columnView == 0);
819
820 // ... and recreate it representing the current mode
821 switch (m_mode) {
822 case IconsView: {
823 m_iconsView = new DolphinIconsView(this, m_controller);
824 view = m_iconsView;
825 break;
826 }
827
828 case DetailsView:
829 m_detailsView = new DolphinDetailsView(this, m_controller);
830 view = m_detailsView;
831 break;
832
833 case ColumnView:
834 m_columnView = new DolphinColumnView(this, m_controller);
835 view = m_columnView;
836 break;
837 }
838
839 Q_ASSERT(view != 0);
840
841 m_fileItemDelegate = new KFileItemDelegate(view);
842 m_fileItemDelegate->setShowInformation(infoList);
843 view->setItemDelegate(m_fileItemDelegate);
844
845 view->setModel(m_proxyModel);
846 view->setSelectionMode(QAbstractItemView::ExtendedSelection);
847
848 new KMimeTypeResolver(view, m_dolphinModel);
849 m_topLayout->insertWidget(1, view);
850
851 connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
852 this, SLOT(emitSelectionChangedSignal()));
853 connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
854 this, SLOT(emitContentsMoved()));
855 connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)),
856 this, SLOT(emitContentsMoved()));
857 view->setFocus();
858 }
859
860 QAbstractItemView* DolphinView::itemView() const
861 {
862 if (m_detailsView != 0) {
863 return m_detailsView;
864 } else if (m_columnView != 0) {
865 return m_columnView;
866 }
867
868 return m_iconsView;
869 }
870
871 bool DolphinView::isValidNameIndex(const QModelIndex& index) const
872 {
873 return index.isValid() && (index.column() == DolphinModel::Name);
874 }
875
876 bool DolphinView::isCutItem(const KFileItem& item) const
877 {
878 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
879 const KUrl::List cutUrls = KUrl::List::fromMimeData(mimeData);
880
881 const KUrl& itemUrl = item.url();
882 KUrl::List::const_iterator it = cutUrls.begin();
883 const KUrl::List::const_iterator end = cutUrls.end();
884 while (it != end) {
885 if (*it == itemUrl) {
886 return true;
887 }
888 ++it;
889 }
890
891 return false;
892 }
893
894 void DolphinView::applyCutItemEffect()
895 {
896 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
897 if (!KonqMimeData::decodeIsCutSelection(mimeData)) {
898 return;
899 }
900
901 KFileItemList items(m_dirLister->items());
902 KFileItemList::const_iterator it = items.begin();
903 const KFileItemList::const_iterator end = items.end();
904 while (it != end) {
905 const KFileItem item = *it;
906 if (isCutItem(item)) {
907 const QModelIndex index = m_dolphinModel->indexForItem(item);
908 const QVariant value = m_dolphinModel->data(index, Qt::DecorationRole);
909 if (value.type() == QVariant::Icon) {
910 const QIcon icon(qvariant_cast<QIcon>(value));
911 QPixmap pixmap = icon.pixmap(128, 128);
912
913 // remember current pixmap for the item to be able
914 // to restore it when other items get cut
915 CutItem cutItem;
916 cutItem.url = item.url();
917 cutItem.pixmap = pixmap;
918 m_cutItemsCache.append(cutItem);
919
920 // apply icon effect to the cut item
921 KIconEffect iconEffect;
922 pixmap = iconEffect.apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
923 m_dolphinModel->setData(index, QIcon(pixmap), Qt::DecorationRole);
924 }
925 }
926 ++it;
927 }
928 }
929
930 #include "dolphinview.moc"