]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinview.cpp
cleanups
[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 <QDropEvent>
26 #include <QItemSelectionModel>
27 #include <QMouseEvent>
28 #include <QVBoxLayout>
29
30 #include <kdirmodel.h>
31 #include <kfileitemdelegate.h>
32 #include <klocale.h>
33 #include <kiconeffect.h>
34 #include <kio/netaccess.h>
35 #include <kio/renamedialog.h>
36 #include <kio/previewjob.h>
37 #include <kmimetyperesolver.h>
38 #include <konqmimedata.h>
39 #include <konq_operations.h>
40 #include <kurl.h>
41
42 #include "dolphincontroller.h"
43 #include "dolphinstatusbar.h"
44 #include "dolphinmainwindow.h"
45 #include "dolphindirlister.h"
46 #include "dolphinsortfilterproxymodel.h"
47 #include "dolphindetailsview.h"
48 #include "dolphiniconsview.h"
49 #include "dolphincontextmenu.h"
50 #include "filterbar.h"
51 #include "renamedialog.h"
52 #include "urlnavigator.h"
53 #include "viewproperties.h"
54 #include "dolphinsettings.h"
55
56 DolphinView::DolphinView(DolphinMainWindow* mainWindow,
57 QWidget* parent,
58 const KUrl& url,
59 Mode mode,
60 bool showHiddenFiles) :
61 QWidget(parent),
62 m_showProgress(false),
63 m_blockContentsMovedSignal(false),
64 m_mode(mode),
65 m_iconSize(0),
66 m_folderCount(0),
67 m_fileCount(0),
68 m_mainWindow(mainWindow),
69 m_topLayout(0),
70 m_urlNavigator(0),
71 m_controller(0),
72 m_iconsView(0),
73 m_detailsView(0),
74 m_fileItemDelegate(0),
75 m_filterBar(0),
76 m_statusBar(0),
77 m_dirModel(0),
78 m_dirLister(0),
79 m_proxyModel(0)
80 {
81 hide();
82 setFocusPolicy(Qt::StrongFocus);
83 m_topLayout = new QVBoxLayout(this);
84 m_topLayout->setSpacing(0);
85 m_topLayout->setMargin(0);
86
87 connect(m_mainWindow, SIGNAL(activeViewChanged()),
88 this, SLOT(updateActivationState()));
89
90 QClipboard* clipboard = QApplication::clipboard();
91 connect(clipboard, SIGNAL(dataChanged()),
92 this, SLOT(updateCutItems()));
93
94 m_urlNavigator = new UrlNavigator(DolphinSettings::instance().bookmarkManager(), url, this);
95 m_urlNavigator->setShowHiddenFiles(showHiddenFiles);
96 connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)),
97 this, SLOT(loadDirectory(const KUrl&)));
98 connect(m_urlNavigator, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)),
99 this, SLOT(dropUrls(const KUrl::List&, const KUrl&)));
100 connect(m_urlNavigator, SIGNAL(activated()),
101 this, SLOT(requestActivation()));
102 connect(this, SIGNAL(contentsMoved(int, int)),
103 m_urlNavigator, SLOT(storeContentsPosition(int, int)));
104
105 m_statusBar = new DolphinStatusBar(this);
106
107 m_dirLister = new DolphinDirLister();
108 m_dirLister->setAutoUpdate(true);
109 m_dirLister->setMainWindow(this);
110 m_dirLister->setShowingDotFiles(showHiddenFiles);
111 m_dirLister->setDelayedMimeTypes(true);
112
113 connect(m_dirLister, SIGNAL(clear()),
114 this, SLOT(updateStatusBar()));
115 connect(m_dirLister, SIGNAL(percent(int)),
116 this, SLOT(updateProgress(int)));
117 connect(m_dirLister, SIGNAL(deleteItem(KFileItem*)),
118 this, SLOT(updateStatusBar()));
119 connect(m_dirLister, SIGNAL(completed()),
120 this, SLOT(updateItemCount()));
121 connect(m_dirLister, SIGNAL(completed()),
122 this, SLOT(updateCutItems()));
123 connect(m_dirLister, SIGNAL(newItems(const KFileItemList&)),
124 this, SLOT(generatePreviews(const KFileItemList&)));
125 connect(m_dirLister, SIGNAL(infoMessage(const QString&)),
126 this, SLOT(showInfoMessage(const QString&)));
127 connect(m_dirLister, SIGNAL(errorMessage(const QString&)),
128 this, SLOT(showErrorMessage(const QString&)));
129
130 m_dirModel = new KDirModel();
131 m_dirModel->setDirLister(m_dirLister);
132 m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory);
133
134 m_proxyModel = new DolphinSortFilterProxyModel(this);
135 m_proxyModel->setSourceModel(m_dirModel);
136
137 m_controller = new DolphinController(this);
138 connect(m_controller, SIGNAL(requestContextMenu(const QPoint&)),
139 this, SLOT(openContextMenu(const QPoint&)));
140 connect(m_controller, SIGNAL(urlsDropped(const KUrl::List&, const QModelIndex&, QWidget*)),
141 this, SLOT(dropUrls(const KUrl::List&, const QModelIndex&, QWidget*)));
142 connect(m_controller, SIGNAL(sortingChanged(DolphinView::Sorting)),
143 this, SLOT(updateSorting(DolphinView::Sorting)));
144 connect(m_controller, SIGNAL(sortOrderChanged(Qt::SortOrder)),
145 this, SLOT(updateSortOrder(Qt::SortOrder)));
146 connect(m_controller, SIGNAL(itemTriggered(const QModelIndex&)),
147 this, SLOT(triggerItem(const QModelIndex&)));
148 connect(m_controller, SIGNAL(selectionChanged()),
149 this, SLOT(emitSelectionChangedSignal()));
150 connect(m_controller, SIGNAL(activated()),
151 this, SLOT(requestActivation()));
152
153 createView();
154
155 m_iconSize = K3Icon::SizeMedium;
156
157 m_filterBar = new FilterBar(this);
158 m_filterBar->hide();
159 connect(m_filterBar, SIGNAL(filterChanged(const QString&)),
160 this, SLOT(changeNameFilter(const QString&)));
161 connect(m_filterBar, SIGNAL(closeRequest()),
162 this, SLOT(closeFilterBar()));
163
164 m_topLayout->addWidget(m_urlNavigator);
165 m_topLayout->addWidget(itemView());
166 m_topLayout->addWidget(m_filterBar);
167 m_topLayout->addWidget(m_statusBar);
168 }
169
170 DolphinView::~DolphinView()
171 {
172 delete m_dirLister;
173 m_dirLister = 0;
174 }
175
176 void DolphinView::setUrl(const KUrl& url)
177 {
178 m_urlNavigator->setUrl(url);
179 m_controller->setUrl(url);
180 }
181
182 const KUrl& DolphinView::url() const
183 {
184 return m_urlNavigator->url();
185 }
186
187 bool DolphinView::isActive() const
188 {
189 return m_mainWindow->activeView() == this;
190 }
191
192 void DolphinView::setMode(Mode mode)
193 {
194 if (mode == m_mode) {
195 return; // the wished mode is already set
196 }
197
198 m_mode = mode;
199
200 ViewProperties props(m_urlNavigator->url());
201 props.setViewMode(m_mode);
202
203 createView();
204 startDirLister(m_urlNavigator->url());
205
206 emit modeChanged();
207 }
208
209 DolphinView::Mode DolphinView::mode() const
210 {
211 return m_mode;
212 }
213
214 void DolphinView::setShowPreview(bool show)
215 {
216 ViewProperties props(m_urlNavigator->url());
217 props.setShowPreview(show);
218
219 m_controller->setShowPreview(show);
220
221 emit showPreviewChanged();
222 reload();
223 }
224
225 bool DolphinView::showPreview() const
226 {
227 return m_controller->showPreview();
228 }
229
230 void DolphinView::setShowHiddenFiles(bool show)
231 {
232 if (m_dirLister->showingDotFiles() == show) {
233 return;
234 }
235
236 ViewProperties props(m_urlNavigator->url());
237 props.setShowHiddenFiles(show);
238 props.save();
239
240 m_dirLister->setShowingDotFiles(show);
241 m_urlNavigator->setShowHiddenFiles(show);
242
243 emit showHiddenFilesChanged();
244
245 reload();
246 }
247
248 bool DolphinView::showHiddenFiles() const
249 {
250 return m_dirLister->showingDotFiles();
251 }
252
253 void DolphinView::renameSelectedItems()
254 {
255 DolphinView* view = mainWindow()->activeView();
256 const KUrl::List urls = selectedUrls();
257 if (urls.count() > 1) {
258 // More than one item has been selected for renaming. Open
259 // a rename dialog and rename all items afterwards.
260 RenameDialog dialog(urls);
261 if (dialog.exec() == QDialog::Rejected) {
262 return;
263 }
264
265 const QString& newName = dialog.newName();
266 if (newName.isEmpty()) {
267 view->statusBar()->setMessage(dialog.errorString(),
268 DolphinStatusBar::Error);
269 }
270 else {
271 // TODO: check how this can be integrated into KonqUndoManager/KonqOperations
272 // as one operation instead of n rename operations like it is done now...
273 Q_ASSERT(newName.contains('#'));
274
275 // iterate through all selected items and rename them...
276 const int replaceIndex = newName.indexOf('#');
277 Q_ASSERT(replaceIndex >= 0);
278 int index = 1;
279
280 KUrl::List::const_iterator it = urls.begin();
281 KUrl::List::const_iterator end = urls.end();
282 while (it != end) {
283 const KUrl& oldUrl = *it;
284 QString number;
285 number.setNum(index++);
286
287 QString name(newName);
288 name.replace(replaceIndex, 1, number);
289
290 if (oldUrl.fileName() != name) {
291 KUrl newUrl(oldUrl.upUrl());
292 newUrl.addPath(name);
293 m_mainWindow->rename(oldUrl, newUrl);
294 }
295 ++it;
296 }
297 }
298 }
299 else {
300 // Only one item has been selected for renaming. Use the custom
301 // renaming mechanism from the views.
302 Q_ASSERT(urls.count() == 1);
303
304 // TODO: Think about using KFileItemDelegate as soon as it supports editing.
305 // Currently the RenameDialog is used, but I'm not sure whether inline renaming
306 // is a benefit for the user at all -> let's wait for some input first...
307 RenameDialog dialog(urls);
308 if (dialog.exec() == QDialog::Rejected) {
309 return;
310 }
311
312 const QString& newName = dialog.newName();
313 if (newName.isEmpty()) {
314 view->statusBar()->setMessage(dialog.errorString(),
315 DolphinStatusBar::Error);
316 }
317 else {
318 const KUrl& oldUrl = urls.first();
319 KUrl newUrl = oldUrl.upUrl();
320 newUrl.addPath(newName);
321 m_mainWindow->rename(oldUrl, newUrl);
322 }
323 }
324 }
325
326 void DolphinView::selectAll()
327 {
328 selectAll(QItemSelectionModel::Select);
329 }
330
331 void DolphinView::invertSelection()
332 {
333 selectAll(QItemSelectionModel::Toggle);
334 }
335
336 DolphinStatusBar* DolphinView::statusBar() const
337 {
338 return m_statusBar;
339 }
340
341 int DolphinView::contentsX() const
342 {
343
344 return itemView()->horizontalScrollBar()->value();
345 }
346
347 int DolphinView::contentsY() const
348 {
349 return itemView()->verticalScrollBar()->value();
350 }
351
352 void DolphinView::refreshSettings()
353 {
354 startDirLister(m_urlNavigator->url());
355 }
356
357 void DolphinView::emitRequestItemInfo(const KUrl& url)
358 {
359 emit requestItemInfo(url);
360 }
361
362 bool DolphinView::isFilterBarVisible() const
363 {
364 return m_filterBar->isVisible();
365 }
366
367 bool DolphinView::isUrlEditable() const
368 {
369 return m_urlNavigator->isUrlEditable();
370 }
371
372 void DolphinView::zoomIn()
373 {
374 m_controller->triggerZoomIn();
375 }
376
377 void DolphinView::zoomOut()
378 {
379 m_controller->triggerZoomOut();
380 }
381
382 bool DolphinView::isZoomInPossible() const
383 {
384 return m_controller->isZoomInPossible();
385 }
386
387 bool DolphinView::isZoomOutPossible() const
388 {
389 return m_controller->isZoomOutPossible();
390 }
391
392 void DolphinView::setSorting(Sorting sorting)
393 {
394 if (sorting != this->sorting()) {
395 updateSorting(sorting);
396 }
397 }
398
399 DolphinView::Sorting DolphinView::sorting() const
400 {
401 return m_proxyModel->sorting();
402 }
403
404 void DolphinView::setSortOrder(Qt::SortOrder order)
405 {
406 if (sortOrder() != order) {
407 updateSortOrder(order);
408 }
409 }
410
411 Qt::SortOrder DolphinView::sortOrder() const
412 {
413 return m_proxyModel->sortOrder();
414 }
415
416 void DolphinView::setAdditionalInfo(KFileItemDelegate::AdditionalInformation info)
417 {
418 ViewProperties props(m_urlNavigator->url());
419 props.setAdditionalInfo(info);
420
421 m_fileItemDelegate->setAdditionalInformation(info);
422
423 emit additionalInfoChanged(info);
424 reload();
425 }
426
427 KFileItemDelegate::AdditionalInformation DolphinView::additionalInfo() const
428 {
429 return m_fileItemDelegate->additionalInformation();
430 }
431
432 void DolphinView::goBack()
433 {
434 m_urlNavigator->goBack();
435 }
436
437 void DolphinView::goForward()
438 {
439 m_urlNavigator->goForward();
440 }
441
442 void DolphinView::goUp()
443 {
444 m_urlNavigator->goUp();
445 }
446
447 void DolphinView::goHome()
448 {
449 m_urlNavigator->goHome();
450 }
451
452 void DolphinView::setUrlEditable(bool editable)
453 {
454 m_urlNavigator->editUrl(editable);
455 }
456
457 const QList<UrlNavigator::HistoryElem> DolphinView::urlHistory(int& index) const
458 {
459 return m_urlNavigator->history(index);
460 }
461
462 bool DolphinView::hasSelection() const
463 {
464 return itemView()->selectionModel()->hasSelection();
465 }
466
467 void DolphinView::clearSelection()
468 {
469 itemView()->selectionModel()->clear();
470 }
471
472 KFileItemList DolphinView::selectedItems() const
473 {
474 const QAbstractItemView* view = itemView();
475
476 // Our view has a selection, we will map them back to the DirModel
477 // and then fill the KFileItemList.
478 Q_ASSERT((view != 0) && (view->selectionModel() != 0));
479
480 const QItemSelection selection = m_proxyModel->mapSelectionToSource(view->selectionModel()->selection());
481 KFileItemList itemList;
482
483 const QModelIndexList indexList = selection.indexes();
484 QModelIndexList::const_iterator end = indexList.end();
485 for (QModelIndexList::const_iterator it = indexList.begin(); it != end; ++it) {
486 Q_ASSERT((*it).isValid());
487
488 KFileItem* item = m_dirModel->itemForIndex(*it);
489 if (item != 0) {
490 itemList.append(item);
491 }
492 }
493
494 return itemList;
495 }
496
497 KUrl::List DolphinView::selectedUrls() const
498 {
499 KUrl::List urls;
500
501 const KFileItemList list = selectedItems();
502 KFileItemList::const_iterator it = list.begin();
503 const KFileItemList::const_iterator end = list.end();
504 while (it != end) {
505 KFileItem* item = *it;
506 urls.append(item->url());
507 ++it;
508 }
509
510 return urls;
511 }
512
513 KFileItem* DolphinView::fileItem(const QModelIndex index) const
514 {
515 const QModelIndex dirModelIndex = m_proxyModel->mapToSource(index);
516 return m_dirModel->itemForIndex(dirModelIndex);
517 }
518
519 void DolphinView::rename(const KUrl& source, const QString& newName)
520 {
521 bool ok = false;
522
523 if (newName.isEmpty() || (source.fileName() == newName)) {
524 return;
525 }
526
527 KUrl dest(source.upUrl());
528 dest.addPath(newName);
529
530 const bool destExists = KIO::NetAccess::exists(dest,
531 false,
532 mainWindow()->activeView());
533 if (destExists) {
534 // the destination already exists, hence ask the user
535 // how to proceed...
536 KIO::RenameDialog renameDialog(this,
537 i18n("File Already Exists"),
538 source.path(),
539 dest.path(),
540 KIO::M_OVERWRITE);
541 switch (renameDialog.exec()) {
542 case KIO::R_OVERWRITE:
543 // the destination should be overwritten
544 ok = KIO::NetAccess::file_move(source, dest, -1, true);
545 break;
546
547 case KIO::R_RENAME: {
548 // a new name for the destination has been used
549 KUrl newDest(renameDialog.newDestUrl());
550 ok = KIO::NetAccess::file_move(source, newDest);
551 break;
552 }
553
554 default:
555 // the renaming operation has been canceled
556 reload();
557 return;
558 }
559 }
560 else {
561 // no destination exists, hence just move the file to
562 // do the renaming
563 ok = KIO::NetAccess::file_move(source, dest);
564 }
565
566 const QString destFileName = dest.fileName();
567 if (ok) {
568 m_statusBar->setMessage(i18n("Renamed file '%1' to '%2'.",source.fileName(), destFileName),
569 DolphinStatusBar::OperationCompleted);
570
571 KonqOperations::rename(this, source, destFileName);
572 }
573 else {
574 m_statusBar->setMessage(i18n("Renaming of file '%1' to '%2' failed.",source.fileName(), destFileName),
575 DolphinStatusBar::Error);
576 reload();
577 }
578 }
579
580 void DolphinView::reload()
581 {
582 startDirLister(m_urlNavigator->url(), true);
583 }
584
585 void DolphinView::mouseReleaseEvent(QMouseEvent* event)
586 {
587 QWidget::mouseReleaseEvent(event);
588 mainWindow()->setActiveView(this);
589 }
590
591 DolphinMainWindow* DolphinView::mainWindow() const
592 {
593 return m_mainWindow;
594 }
595
596 void DolphinView::loadDirectory(const KUrl& url)
597 {
598 if(!isActive()) {
599 requestActivation();
600 }
601
602 const ViewProperties props(url);
603
604 const Mode mode = props.viewMode();
605 if (m_mode != mode) {
606 m_mode = mode;
607 createView();
608 emit modeChanged();
609 }
610
611 const bool showHiddenFiles = props.showHiddenFiles();
612 if (showHiddenFiles != m_dirLister->showingDotFiles()) {
613 m_dirLister->setShowingDotFiles(showHiddenFiles);
614 emit showHiddenFilesChanged();
615 }
616
617 const DolphinView::Sorting sorting = props.sorting();
618 if (sorting != m_proxyModel->sorting()) {
619 m_proxyModel->setSorting(sorting);
620 emit sortingChanged(sorting);
621 }
622
623 const Qt::SortOrder sortOrder = props.sortOrder();
624 if (sortOrder != m_proxyModel->sortOrder()) {
625 m_proxyModel->setSortOrder(sortOrder);
626 emit sortOrderChanged(sortOrder);
627 }
628
629 KFileItemDelegate::AdditionalInformation info = props.additionalInfo();
630 if (info != m_fileItemDelegate->additionalInformation()) {
631 m_fileItemDelegate->setAdditionalInformation(info);
632
633 emit additionalInfoChanged(info);
634 }
635
636 const bool showPreview = props.showPreview();
637 if (showPreview != m_controller->showPreview()) {
638 m_controller->setShowPreview(showPreview);
639 emit showPreviewChanged();
640 }
641
642 startDirLister(url);
643 emit urlChanged(url);
644
645 m_statusBar->clear();
646 }
647
648 void DolphinView::triggerItem(const QModelIndex& index)
649 {
650 if (!isValidNameIndex(index)) {
651 return;
652 }
653
654 const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
655 if ((modifier & Qt::ShiftModifier) || (modifier & Qt::ControlModifier)) {
656 // items are selected by the user, hence don't trigger the
657 // item specified by 'index'
658 return;
659 }
660
661 KFileItem* item = m_dirModel->itemForIndex(m_proxyModel->mapToSource(index));
662 if (item == 0) {
663 return;
664 }
665
666 // Prefer the local path over the URL. This assures that the
667 // volume space information is correct. Assuming that the URL is media:/sda1,
668 // and the local path is /windows/C: For the URL the space info is related
669 // to the root partition (and hence wrong) and for the local path the space
670 // info is related to the windows partition (-> correct).
671 const QString localPath(item->localPath());
672 KUrl url;
673 if (localPath.isEmpty()) {
674 url = item->url();
675 }
676 else {
677 url = localPath;
678 }
679
680 if (item->isDir()) {
681 setUrl(url);
682 }
683 else if (item->isFile()) {
684 // allow to browse through ZIP and tar files
685 KMimeType::Ptr mime = item->mimeTypePtr();
686 if (mime->is("application/zip")) {
687 url.setProtocol("zip");
688 setUrl(url);
689 }
690 else if (mime->is("application/x-tar") ||
691 mime->is("application/x-tarz") ||
692 mime->is("application/x-bzip-compressed-tar") ||
693 mime->is("application/x-compressed-tar") ||
694 mime->is("application/x-tzo")) {
695 url.setProtocol("tar");
696 setUrl(url);
697 }
698 else {
699 item->run();
700 }
701 }
702 else {
703 item->run();
704 }
705 }
706
707 void DolphinView::updateProgress(int percent)
708 {
709 if (m_showProgress) {
710 m_statusBar->setProgress(percent);
711 }
712 }
713
714 void DolphinView::updateItemCount()
715 {
716 if (m_showProgress) {
717 m_statusBar->setProgressText(QString());
718 m_statusBar->setProgress(100);
719 m_showProgress = false;
720 }
721
722 KFileItemList items(m_dirLister->items());
723 KFileItemList::const_iterator it = items.begin();
724 const KFileItemList::const_iterator end = items.end();
725
726 m_fileCount = 0;
727 m_folderCount = 0;
728
729 while (it != end) {
730 KFileItem* item = *it;
731 if (item->isDir()) {
732 ++m_folderCount;
733 }
734 else {
735 ++m_fileCount;
736 }
737 ++it;
738 }
739
740 updateStatusBar();
741
742 m_blockContentsMovedSignal = false;
743 QTimer::singleShot(0, this, SLOT(restoreContentsPos()));
744 }
745
746 void DolphinView::generatePreviews(const KFileItemList& items)
747 {
748 if (m_controller->showPreview()) {
749 KIO::PreviewJob* job = KIO::filePreview(items, 128);
750 connect(job, SIGNAL(gotPreview(const KFileItem*, const QPixmap&)),
751 this, SLOT(showPreview(const KFileItem*, const QPixmap&)));
752 }
753 }
754
755 void DolphinView::showPreview(const KFileItem* item, const QPixmap& pixmap)
756 {
757 Q_ASSERT(item != 0);
758 const QModelIndex idx = m_dirModel->indexForItem(*item);
759 if (idx.isValid() && (idx.column() == 0)) {
760 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
761 if (KonqMimeData::decodeIsCutSelection(mimeData) && isCutItem(*item)) {
762 KIconEffect iconEffect;
763 const QPixmap cutPixmap = iconEffect.apply(pixmap, K3Icon::Desktop, K3Icon::DisabledState);
764 m_dirModel->setData(idx, QIcon(cutPixmap), Qt::DecorationRole);
765 }
766 else {
767 m_dirModel->setData(idx, QIcon(pixmap), Qt::DecorationRole);
768 }
769 }
770 }
771
772 void DolphinView::restoreContentsPos()
773 {
774 int index = 0;
775 const QList<UrlNavigator::HistoryElem> history = urlHistory(index);
776 if (!history.isEmpty()) {
777 QAbstractItemView* view = itemView();
778 // TODO: view->setCurrentItem(history[index].currentFileName());
779
780 const UrlNavigator::HistoryElem& it = history[index];
781 view->horizontalScrollBar()->setValue(it.contentsX());
782 view->verticalScrollBar()->setValue(it.contentsY());
783 }
784 }
785
786 void DolphinView::showInfoMessage(const QString& msg)
787 {
788 m_statusBar->setMessage(msg, DolphinStatusBar::Information);
789 }
790
791 void DolphinView::showErrorMessage(const QString& msg)
792 {
793 m_statusBar->setMessage(msg, DolphinStatusBar::Error);
794 }
795
796 void DolphinView::emitSelectionChangedSignal()
797 {
798 emit selectionChanged(DolphinView::selectedItems());
799 }
800
801 void DolphinView::closeFilterBar()
802 {
803 m_filterBar->hide();
804 emit showFilterBarChanged(false);
805 }
806
807 void DolphinView::startDirLister(const KUrl& url, bool reload)
808 {
809 if (!url.isValid()) {
810 const QString location(url.pathOrUrl());
811 if (location.isEmpty()) {
812 m_statusBar->setMessage(i18n("The location is empty."), DolphinStatusBar::Error);
813 }
814 else {
815 m_statusBar->setMessage(i18n("The location '%1' is invalid.",location),
816 DolphinStatusBar::Error);
817 }
818 return;
819 }
820
821 // Only show the directory loading progress if the status bar does
822 // not contain another progress information. This means that
823 // the directory loading progress information has the lowest priority.
824 const QString progressText(m_statusBar->progressText());
825 m_showProgress = progressText.isEmpty() ||
826 (progressText == i18n("Loading directory..."));
827 if (m_showProgress) {
828 m_statusBar->setProgressText(i18n("Loading directory..."));
829 m_statusBar->setProgress(0);
830 }
831
832 m_cutItemsCache.clear();
833 m_blockContentsMovedSignal = true;
834 m_dirLister->stop();
835 m_dirLister->openUrl(url, false, reload);
836 }
837
838 QString DolphinView::defaultStatusBarText() const
839 {
840 return KIO::itemsSummaryString(m_fileCount + m_folderCount,
841 m_fileCount,
842 m_folderCount,
843 0, false);
844 }
845
846 QString DolphinView::selectionStatusBarText() const
847 {
848 QString text;
849 const KFileItemList list = selectedItems();
850 if (list.isEmpty()) {
851 // when an item is triggered, it is temporary selected but selectedItems()
852 // will return an empty list
853 return QString();
854 }
855
856 int fileCount = 0;
857 int folderCount = 0;
858 KIO::filesize_t byteSize = 0;
859 KFileItemList::const_iterator it = list.begin();
860 const KFileItemList::const_iterator end = list.end();
861 while (it != end){
862 KFileItem* item = *it;
863 if (item->isDir()) {
864 ++folderCount;
865 }
866 else {
867 ++fileCount;
868 byteSize += item->size();
869 }
870 ++it;
871 }
872
873 if (folderCount > 0) {
874 text = i18np("1 Folder selected", "%1 Folders selected", folderCount);
875 if (fileCount > 0) {
876 text += ", ";
877 }
878 }
879
880 if (fileCount > 0) {
881 const QString sizeText(KIO::convertSize(byteSize));
882 text += i18np("1 File selected (%2)", "%1 Files selected (%2)", fileCount, sizeText);
883 }
884
885 return text;
886 }
887
888 void DolphinView::showFilterBar(bool show)
889 {
890 Q_ASSERT(m_filterBar != 0);
891 if (show) {
892 m_filterBar->show();
893 }
894 else {
895 m_filterBar->hide();
896 }
897 }
898
899 void DolphinView::updateStatusBar()
900 {
901 // As the item count information is less important
902 // in comparison with other messages, it should only
903 // be shown if:
904 // - the status bar is empty or
905 // - shows already the item count information or
906 // - shows only a not very important information
907 // - if any progress is given don't show the item count info at all
908 const QString msg(m_statusBar->message());
909 const bool updateStatusBarMsg = (msg.isEmpty() ||
910 (msg == m_statusBar->defaultText()) ||
911 (m_statusBar->type() == DolphinStatusBar::Information)) &&
912 (m_statusBar->progress() == 100);
913
914 const QString text(hasSelection() ? selectionStatusBarText() : defaultStatusBarText());
915 m_statusBar->setDefaultText(text);
916
917 if (updateStatusBarMsg) {
918 m_statusBar->setMessage(text, DolphinStatusBar::Default);
919 }
920 }
921
922 void DolphinView::requestActivation()
923 {
924 m_mainWindow->setActiveView(this);
925 }
926
927 void DolphinView::changeSelection(const KFileItemList& selection)
928 {
929 clearSelection();
930 if (selection.isEmpty()) {
931 return;
932 }
933 KUrl baseUrl = url();
934 KUrl url;
935 QItemSelection new_selection;
936 foreach (KFileItem* item, selection) {
937 url = item->url().upUrl();
938 if (baseUrl.equals(url, KUrl::CompareWithoutTrailingSlash)) {
939 QModelIndex index = m_proxyModel->mapFromSource(m_dirModel->indexForItem(*item));
940 new_selection.select(index, index);
941 }
942 }
943 itemView()->selectionModel()->select(new_selection,
944 QItemSelectionModel::ClearAndSelect
945 | QItemSelectionModel::Current);
946 }
947
948 void DolphinView::changeNameFilter(const QString& nameFilter)
949 {
950 // The name filter of KDirLister does a 'hard' filtering, which
951 // means that only the items are shown where the names match
952 // exactly the filter. This is non-transparent for the user, which
953 // just wants to have a 'soft' filtering: does the name contain
954 // the filter string?
955 QString adjustedFilter(nameFilter);
956 adjustedFilter.insert(0, '*');
957 adjustedFilter.append('*');
958
959 // Use the ProxyModel to filter:
960 // This code is #ifdefed as setNameFilter behaves
961 // slightly different than the QSortFilterProxyModel
962 // as it will not remove directories. I will ask
963 // our beloved usability experts for input
964 // -- z.
965 #if 0
966 m_dirLister->setNameFilter(adjustedFilter);
967 m_dirLister->emitChanges();
968 #else
969 m_proxyModel->setFilterRegExp( nameFilter );
970 #endif
971 }
972
973 void DolphinView::openContextMenu(const QPoint& pos)
974 {
975 KFileItem* item = 0;
976
977 const QModelIndex index = itemView()->indexAt(pos);
978 if (isValidNameIndex(index)) {
979 item = fileItem(index);
980 }
981
982 DolphinContextMenu contextMenu(m_mainWindow, item, url());
983 contextMenu.open();
984 }
985
986 void DolphinView::dropUrls(const KUrl::List& urls,
987 const QModelIndex& index,
988 QWidget* source)
989 {
990 KFileItem* directory = 0;
991 if (isValidNameIndex(index)) {
992 KFileItem* item = fileItem(index);
993 Q_ASSERT(item != 0);
994 if (item->isDir()) {
995 // the URLs are dropped above a directory
996 directory = item;
997 }
998 }
999
1000 if ((directory == 0) && (source == itemView())) {
1001 // The dropping is done into the same viewport where
1002 // the dragging has been started. Just ignore this...
1003 return;
1004 }
1005
1006 const KUrl& destination = (directory == 0) ? url() :
1007 directory->url();
1008 dropUrls(urls, destination);
1009 }
1010
1011 void DolphinView::dropUrls(const KUrl::List& urls,
1012 const KUrl& destination)
1013 {
1014 m_mainWindow->dropUrls(urls, destination);
1015 }
1016
1017 void DolphinView::updateSorting(DolphinView::Sorting sorting)
1018 {
1019 ViewProperties props(url());
1020 props.setSorting(sorting);
1021
1022 m_proxyModel->setSorting(sorting);
1023
1024 emit sortingChanged(sorting);
1025 }
1026
1027 void DolphinView::updateSortOrder(Qt::SortOrder order)
1028 {
1029 ViewProperties props(url());
1030 props.setSortOrder(order);
1031
1032 m_proxyModel->setSortOrder(order);
1033
1034 emit sortOrderChanged(order);
1035 }
1036
1037 void DolphinView::emitContentsMoved()
1038 {
1039 if (!m_blockContentsMovedSignal) {
1040 emit contentsMoved(contentsX(), contentsY());
1041 }
1042 }
1043
1044 void DolphinView::updateActivationState()
1045 {
1046 m_urlNavigator->setActive(isActive());
1047 if(isActive()) {
1048 emit urlChanged(url());
1049 emit selectionChanged(selectedItems());
1050 }
1051 }
1052
1053 void DolphinView::updateCutItems()
1054 {
1055 // restore the icons of all previously selected items to the
1056 // original state...
1057 QList<CutItem>::const_iterator it = m_cutItemsCache.begin();
1058 QList<CutItem>::const_iterator end = m_cutItemsCache.end();
1059 while (it != end) {
1060 const QModelIndex index = m_dirModel->indexForUrl((*it).url);
1061 if (index.isValid()) {
1062 m_dirModel->setData(index, QIcon((*it).pixmap), Qt::DecorationRole);
1063 }
1064 ++it;
1065 }
1066 m_cutItemsCache.clear();
1067
1068 // ... and apply an item effect to all currently cut items
1069 applyCutItemEffect();
1070 }
1071
1072 void DolphinView::createView()
1073 {
1074 // delete current view
1075 QAbstractItemView* view = itemView();
1076 if (view != 0) {
1077 m_topLayout->removeWidget(view);
1078 view->close();
1079 view->deleteLater();
1080 view = 0;
1081 m_iconsView = 0;
1082 m_detailsView = 0;
1083 m_fileItemDelegate = 0;
1084 }
1085
1086 Q_ASSERT(m_iconsView == 0);
1087 Q_ASSERT(m_detailsView == 0);
1088
1089 // ... and recreate it representing the current mode
1090 switch (m_mode) {
1091 case IconsView:
1092 m_iconsView = new DolphinIconsView(this, m_controller);
1093 view = m_iconsView;
1094 break;
1095
1096 case DetailsView:
1097 m_detailsView = new DolphinDetailsView(this, m_controller);
1098 view = m_detailsView;
1099 break;
1100 }
1101
1102 Q_ASSERT(view != 0);
1103
1104 m_fileItemDelegate = new KFileItemDelegate(view);
1105 view->setItemDelegate(m_fileItemDelegate);
1106
1107 view->setModel(m_proxyModel);
1108 view->setSelectionMode(QAbstractItemView::ExtendedSelection);
1109
1110 new KMimeTypeResolver(view, m_dirModel);
1111 m_topLayout->insertWidget(1, view);
1112
1113 connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
1114 m_controller, SLOT(indicateSelectionChange()));
1115 connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
1116 this, SLOT(emitContentsMoved()));
1117 connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)),
1118 this, SLOT(emitContentsMoved()));
1119 }
1120
1121 void DolphinView::selectAll(QItemSelectionModel::SelectionFlags flags)
1122 {
1123 QItemSelectionModel* selectionModel = itemView()->selectionModel();
1124 const QAbstractItemModel* itemModel = selectionModel->model();
1125
1126 const QModelIndex topLeft = itemModel->index(0, 0);
1127 const QModelIndex bottomRight = itemModel->index(itemModel->rowCount() - 1,
1128 itemModel->columnCount() - 1);
1129
1130 QItemSelection selection(topLeft, bottomRight);
1131 selectionModel->select(selection, flags);
1132 }
1133
1134 QAbstractItemView* DolphinView::itemView() const
1135 {
1136 Q_ASSERT((m_iconsView == 0) || (m_detailsView == 0));
1137 if (m_detailsView != 0) {
1138 return m_detailsView;
1139 }
1140 return m_iconsView;
1141 }
1142
1143 bool DolphinView::isValidNameIndex(const QModelIndex& index) const
1144 {
1145 return index.isValid() && (index.column() == KDirModel::Name);
1146 }
1147
1148 bool DolphinView::isCutItem(const KFileItem& item) const
1149 {
1150 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
1151 const KUrl::List cutUrls = KUrl::List::fromMimeData(mimeData);
1152
1153 const KUrl& itemUrl = item.url();
1154 KUrl::List::const_iterator it = cutUrls.begin();
1155 const KUrl::List::const_iterator end = cutUrls.end();
1156 while (it != end){
1157 if (*it == itemUrl) {
1158 return true;
1159 }
1160 ++it;
1161 }
1162
1163 return false;
1164 }
1165
1166 void DolphinView::applyCutItemEffect()
1167 {
1168 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
1169 if (!KonqMimeData::decodeIsCutSelection(mimeData)) {
1170 return;
1171 }
1172
1173 KFileItemList items(m_dirLister->items());
1174 KFileItemList::const_iterator it = items.begin();
1175 const KFileItemList::const_iterator end = items.end();
1176 while (it != end) {
1177 KFileItem* item = *it;
1178 if (isCutItem(*item)) {
1179 const QModelIndex index = m_dirModel->indexForItem(*item);
1180 const KFileItem* item = m_dirModel->itemForIndex(index);
1181 const QVariant value = m_dirModel->data(index, Qt::DecorationRole);
1182 if ((value.type() == QVariant::Icon) && (item != 0)) {
1183 const QIcon icon(qvariant_cast<QIcon>(value));
1184 QPixmap pixmap = icon.pixmap(128, 128);
1185
1186 // remember current pixmap for the item to be able
1187 // to restore it when other items get cut
1188 CutItem cutItem;
1189 cutItem.url = item->url();
1190 cutItem.pixmap = pixmap;
1191 m_cutItemsCache.append(cutItem);
1192
1193 // apply icon effect to the cut item
1194 KIconEffect iconEffect;
1195 pixmap = iconEffect.apply(pixmap, K3Icon::Desktop, K3Icon::DisabledState);
1196 m_dirModel->setData(index, QIcon(pixmap), Qt::DecorationRole);
1197 }
1198 }
1199 ++it;
1200 }
1201 }
1202
1203 #include "dolphinview.moc"