]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinview.cpp
Ported to KBookmarkManager::closestBookmark - which even solves another TODO about...
[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 bool DolphinView::hasSelection() const
458 {
459 return itemView()->selectionModel()->hasSelection();
460 }
461
462 void DolphinView::clearSelection()
463 {
464 itemView()->selectionModel()->clear();
465 }
466
467 KFileItemList DolphinView::selectedItems() const
468 {
469 const QAbstractItemView* view = itemView();
470
471 // Our view has a selection, we will map them back to the DirModel
472 // and then fill the KFileItemList.
473 Q_ASSERT((view != 0) && (view->selectionModel() != 0));
474
475 const QItemSelection selection = m_proxyModel->mapSelectionToSource(view->selectionModel()->selection());
476 KFileItemList itemList;
477
478 const QModelIndexList indexList = selection.indexes();
479 QModelIndexList::const_iterator end = indexList.end();
480 for (QModelIndexList::const_iterator it = indexList.begin(); it != end; ++it) {
481 Q_ASSERT((*it).isValid());
482
483 KFileItem* item = m_dirModel->itemForIndex(*it);
484 if (item != 0) {
485 itemList.append(item);
486 }
487 }
488
489 return itemList;
490 }
491
492 KUrl::List DolphinView::selectedUrls() const
493 {
494 KUrl::List urls;
495
496 const KFileItemList list = selectedItems();
497 KFileItemList::const_iterator it = list.begin();
498 const KFileItemList::const_iterator end = list.end();
499 while (it != end) {
500 KFileItem* item = *it;
501 urls.append(item->url());
502 ++it;
503 }
504
505 return urls;
506 }
507
508 KFileItem* DolphinView::fileItem(const QModelIndex index) const
509 {
510 const QModelIndex dirModelIndex = m_proxyModel->mapToSource(index);
511 return m_dirModel->itemForIndex(dirModelIndex);
512 }
513
514 void DolphinView::rename(const KUrl& source, const QString& newName)
515 {
516 bool ok = false;
517
518 if (newName.isEmpty() || (source.fileName() == newName)) {
519 return;
520 }
521
522 KUrl dest(source.upUrl());
523 dest.addPath(newName);
524
525 const bool destExists = KIO::NetAccess::exists(dest,
526 false,
527 mainWindow()->activeView());
528 if (destExists) {
529 // the destination already exists, hence ask the user
530 // how to proceed...
531 KIO::RenameDialog renameDialog(this,
532 i18n("File Already Exists"),
533 source.path(),
534 dest.path(),
535 KIO::M_OVERWRITE);
536 switch (renameDialog.exec()) {
537 case KIO::R_OVERWRITE:
538 // the destination should be overwritten
539 ok = KIO::NetAccess::file_move(source, dest, -1, true);
540 break;
541
542 case KIO::R_RENAME: {
543 // a new name for the destination has been used
544 KUrl newDest(renameDialog.newDestUrl());
545 ok = KIO::NetAccess::file_move(source, newDest);
546 break;
547 }
548
549 default:
550 // the renaming operation has been canceled
551 reload();
552 return;
553 }
554 }
555 else {
556 // no destination exists, hence just move the file to
557 // do the renaming
558 ok = KIO::NetAccess::file_move(source, dest);
559 }
560
561 const QString destFileName = dest.fileName();
562 if (ok) {
563 m_statusBar->setMessage(i18n("Renamed file '%1' to '%2'.",source.fileName(), destFileName),
564 DolphinStatusBar::OperationCompleted);
565
566 KonqOperations::rename(this, source, destFileName);
567 }
568 else {
569 m_statusBar->setMessage(i18n("Renaming of file '%1' to '%2' failed.",source.fileName(), destFileName),
570 DolphinStatusBar::Error);
571 reload();
572 }
573 }
574
575 void DolphinView::reload()
576 {
577 startDirLister(m_urlNavigator->url(), true);
578 }
579
580 void DolphinView::mouseReleaseEvent(QMouseEvent* event)
581 {
582 QWidget::mouseReleaseEvent(event);
583 mainWindow()->setActiveView(this);
584 }
585
586 DolphinMainWindow* DolphinView::mainWindow() const
587 {
588 return m_mainWindow;
589 }
590
591 void DolphinView::loadDirectory(const KUrl& url)
592 {
593 if(!isActive()) {
594 requestActivation();
595 }
596
597 const ViewProperties props(url);
598
599 const Mode mode = props.viewMode();
600 if (m_mode != mode) {
601 m_mode = mode;
602 createView();
603 emit modeChanged();
604 }
605
606 const bool showHiddenFiles = props.showHiddenFiles();
607 if (showHiddenFiles != m_dirLister->showingDotFiles()) {
608 m_dirLister->setShowingDotFiles(showHiddenFiles);
609 emit showHiddenFilesChanged();
610 }
611
612 const DolphinView::Sorting sorting = props.sorting();
613 if (sorting != m_proxyModel->sorting()) {
614 m_proxyModel->setSorting(sorting);
615 emit sortingChanged(sorting);
616 }
617
618 const Qt::SortOrder sortOrder = props.sortOrder();
619 if (sortOrder != m_proxyModel->sortOrder()) {
620 m_proxyModel->setSortOrder(sortOrder);
621 emit sortOrderChanged(sortOrder);
622 }
623
624 KFileItemDelegate::AdditionalInformation info = props.additionalInfo();
625 if (info != m_fileItemDelegate->additionalInformation()) {
626 m_fileItemDelegate->setAdditionalInformation(info);
627
628 emit additionalInfoChanged(info);
629 }
630
631 const bool showPreview = props.showPreview();
632 if (showPreview != m_controller->showPreview()) {
633 m_controller->setShowPreview(showPreview);
634 emit showPreviewChanged();
635 }
636
637 startDirLister(url);
638 emit urlChanged(url);
639
640 m_statusBar->clear();
641 }
642
643 void DolphinView::triggerItem(const QModelIndex& index)
644 {
645 if (!isValidNameIndex(index)) {
646 return;
647 }
648
649 const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
650 if ((modifier & Qt::ShiftModifier) || (modifier & Qt::ControlModifier)) {
651 // items are selected by the user, hence don't trigger the
652 // item specified by 'index'
653 return;
654 }
655
656 KFileItem* item = m_dirModel->itemForIndex(m_proxyModel->mapToSource(index));
657 if (item == 0) {
658 return;
659 }
660
661 // Prefer the local path over the URL. This assures that the
662 // volume space information is correct. Assuming that the URL is media:/sda1,
663 // and the local path is /windows/C: For the URL the space info is related
664 // to the root partition (and hence wrong) and for the local path the space
665 // info is related to the windows partition (-> correct).
666 const QString localPath(item->localPath());
667 KUrl url;
668 if (localPath.isEmpty()) {
669 url = item->url();
670 }
671 else {
672 url = localPath;
673 }
674
675 if (item->isDir()) {
676 setUrl(url);
677 }
678 else if (item->isFile()) {
679 // allow to browse through ZIP and tar files
680 KMimeType::Ptr mime = item->mimeTypePtr();
681 if (mime->is("application/zip")) {
682 url.setProtocol("zip");
683 setUrl(url);
684 }
685 else if (mime->is("application/x-tar") ||
686 mime->is("application/x-tarz") ||
687 mime->is("application/x-bzip-compressed-tar") ||
688 mime->is("application/x-compressed-tar") ||
689 mime->is("application/x-tzo")) {
690 url.setProtocol("tar");
691 setUrl(url);
692 }
693 else {
694 item->run();
695 }
696 }
697 else {
698 item->run();
699 }
700 }
701
702 void DolphinView::updateProgress(int percent)
703 {
704 if (m_showProgress) {
705 m_statusBar->setProgress(percent);
706 }
707 }
708
709 void DolphinView::updateItemCount()
710 {
711 if (m_showProgress) {
712 m_statusBar->setProgressText(QString());
713 m_statusBar->setProgress(100);
714 m_showProgress = false;
715 }
716
717 KFileItemList items(m_dirLister->items());
718 KFileItemList::const_iterator it = items.begin();
719 const KFileItemList::const_iterator end = items.end();
720
721 m_fileCount = 0;
722 m_folderCount = 0;
723
724 while (it != end) {
725 KFileItem* item = *it;
726 if (item->isDir()) {
727 ++m_folderCount;
728 }
729 else {
730 ++m_fileCount;
731 }
732 ++it;
733 }
734
735 updateStatusBar();
736
737 m_blockContentsMovedSignal = false;
738 QTimer::singleShot(0, this, SLOT(restoreContentsPos()));
739 }
740
741 void DolphinView::generatePreviews(const KFileItemList& items)
742 {
743 if (m_controller->showPreview()) {
744 KIO::PreviewJob* job = KIO::filePreview(items, 128);
745 connect(job, SIGNAL(gotPreview(const KFileItem*, const QPixmap&)),
746 this, SLOT(showPreview(const KFileItem*, const QPixmap&)));
747 }
748 }
749
750 void DolphinView::showPreview(const KFileItem* item, const QPixmap& pixmap)
751 {
752 Q_ASSERT(item != 0);
753 const QModelIndex idx = m_dirModel->indexForItem(*item);
754 if (idx.isValid() && (idx.column() == 0)) {
755 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
756 if (KonqMimeData::decodeIsCutSelection(mimeData) && isCutItem(*item)) {
757 KIconEffect iconEffect;
758 const QPixmap cutPixmap = iconEffect.apply(pixmap, K3Icon::Desktop, K3Icon::DisabledState);
759 m_dirModel->setData(idx, QIcon(cutPixmap), Qt::DecorationRole);
760 }
761 else {
762 m_dirModel->setData(idx, QIcon(pixmap), Qt::DecorationRole);
763 }
764 }
765 }
766
767 void DolphinView::restoreContentsPos()
768 {
769 UrlNavigator::HistoryElem historyItem = m_urlNavigator->currentHistoryItem();
770 if (!historyItem.url().isEmpty()) {
771 QAbstractItemView* view = itemView();
772 // TODO: view->setCurrentItem(historyItem.currentFileName());
773 view->horizontalScrollBar()->setValue(historyItem.contentsX());
774 view->verticalScrollBar()->setValue(historyItem.contentsY());
775 }
776 }
777
778 void DolphinView::showInfoMessage(const QString& msg)
779 {
780 m_statusBar->setMessage(msg, DolphinStatusBar::Information);
781 }
782
783 void DolphinView::showErrorMessage(const QString& msg)
784 {
785 m_statusBar->setMessage(msg, DolphinStatusBar::Error);
786 }
787
788 void DolphinView::emitSelectionChangedSignal()
789 {
790 emit selectionChanged(DolphinView::selectedItems());
791 }
792
793 void DolphinView::closeFilterBar()
794 {
795 m_filterBar->hide();
796 emit showFilterBarChanged(false);
797 }
798
799 void DolphinView::startDirLister(const KUrl& url, bool reload)
800 {
801 if (!url.isValid()) {
802 const QString location(url.pathOrUrl());
803 if (location.isEmpty()) {
804 m_statusBar->setMessage(i18n("The location is empty."), DolphinStatusBar::Error);
805 }
806 else {
807 m_statusBar->setMessage(i18n("The location '%1' is invalid.",location),
808 DolphinStatusBar::Error);
809 }
810 return;
811 }
812
813 // Only show the directory loading progress if the status bar does
814 // not contain another progress information. This means that
815 // the directory loading progress information has the lowest priority.
816 const QString progressText(m_statusBar->progressText());
817 m_showProgress = progressText.isEmpty() ||
818 (progressText == i18n("Loading directory..."));
819 if (m_showProgress) {
820 m_statusBar->setProgressText(i18n("Loading directory..."));
821 m_statusBar->setProgress(0);
822 }
823
824 m_cutItemsCache.clear();
825 m_blockContentsMovedSignal = true;
826 m_dirLister->stop();
827 m_dirLister->openUrl(url, false, reload);
828 }
829
830 QString DolphinView::defaultStatusBarText() const
831 {
832 return KIO::itemsSummaryString(m_fileCount + m_folderCount,
833 m_fileCount,
834 m_folderCount,
835 0, false);
836 }
837
838 QString DolphinView::selectionStatusBarText() const
839 {
840 QString text;
841 const KFileItemList list = selectedItems();
842 if (list.isEmpty()) {
843 // when an item is triggered, it is temporary selected but selectedItems()
844 // will return an empty list
845 return QString();
846 }
847
848 int fileCount = 0;
849 int folderCount = 0;
850 KIO::filesize_t byteSize = 0;
851 KFileItemList::const_iterator it = list.begin();
852 const KFileItemList::const_iterator end = list.end();
853 while (it != end){
854 KFileItem* item = *it;
855 if (item->isDir()) {
856 ++folderCount;
857 }
858 else {
859 ++fileCount;
860 byteSize += item->size();
861 }
862 ++it;
863 }
864
865 if (folderCount > 0) {
866 text = i18np("1 Folder selected", "%1 Folders selected", folderCount);
867 if (fileCount > 0) {
868 text += ", ";
869 }
870 }
871
872 if (fileCount > 0) {
873 const QString sizeText(KIO::convertSize(byteSize));
874 text += i18np("1 File selected (%2)", "%1 Files selected (%2)", fileCount, sizeText);
875 }
876
877 return text;
878 }
879
880 void DolphinView::showFilterBar(bool show)
881 {
882 Q_ASSERT(m_filterBar != 0);
883 if (show) {
884 m_filterBar->show();
885 }
886 else {
887 m_filterBar->hide();
888 }
889 }
890
891 void DolphinView::updateStatusBar()
892 {
893 // As the item count information is less important
894 // in comparison with other messages, it should only
895 // be shown if:
896 // - the status bar is empty or
897 // - shows already the item count information or
898 // - shows only a not very important information
899 // - if any progress is given don't show the item count info at all
900 const QString msg(m_statusBar->message());
901 const bool updateStatusBarMsg = (msg.isEmpty() ||
902 (msg == m_statusBar->defaultText()) ||
903 (m_statusBar->type() == DolphinStatusBar::Information)) &&
904 (m_statusBar->progress() == 100);
905
906 const QString text(hasSelection() ? selectionStatusBarText() : defaultStatusBarText());
907 m_statusBar->setDefaultText(text);
908
909 if (updateStatusBarMsg) {
910 m_statusBar->setMessage(text, DolphinStatusBar::Default);
911 }
912 }
913
914 void DolphinView::requestActivation()
915 {
916 m_mainWindow->setActiveView(this);
917 }
918
919 void DolphinView::changeSelection(const KFileItemList& selection)
920 {
921 clearSelection();
922 if (selection.isEmpty()) {
923 return;
924 }
925 KUrl baseUrl = url();
926 KUrl url;
927 QItemSelection new_selection;
928 foreach (KFileItem* item, selection) {
929 url = item->url().upUrl();
930 if (baseUrl.equals(url, KUrl::CompareWithoutTrailingSlash)) {
931 QModelIndex index = m_proxyModel->mapFromSource(m_dirModel->indexForItem(*item));
932 new_selection.select(index, index);
933 }
934 }
935 itemView()->selectionModel()->select(new_selection,
936 QItemSelectionModel::ClearAndSelect
937 | QItemSelectionModel::Current);
938 }
939
940 void DolphinView::changeNameFilter(const QString& nameFilter)
941 {
942 // The name filter of KDirLister does a 'hard' filtering, which
943 // means that only the items are shown where the names match
944 // exactly the filter. This is non-transparent for the user, which
945 // just wants to have a 'soft' filtering: does the name contain
946 // the filter string?
947 QString adjustedFilter(nameFilter);
948 adjustedFilter.insert(0, '*');
949 adjustedFilter.append('*');
950
951 // Use the ProxyModel to filter:
952 // This code is #ifdefed as setNameFilter behaves
953 // slightly different than the QSortFilterProxyModel
954 // as it will not remove directories. I will ask
955 // our beloved usability experts for input
956 // -- z.
957 #if 0
958 m_dirLister->setNameFilter(adjustedFilter);
959 m_dirLister->emitChanges();
960 #else
961 m_proxyModel->setFilterRegExp( nameFilter );
962 #endif
963 }
964
965 void DolphinView::openContextMenu(const QPoint& pos)
966 {
967 KFileItem* item = 0;
968
969 const QModelIndex index = itemView()->indexAt(pos);
970 if (isValidNameIndex(index)) {
971 item = fileItem(index);
972 }
973
974 DolphinContextMenu contextMenu(m_mainWindow, item, url());
975 contextMenu.open();
976 }
977
978 void DolphinView::dropUrls(const KUrl::List& urls,
979 const QModelIndex& index,
980 QWidget* source)
981 {
982 KFileItem* directory = 0;
983 if (isValidNameIndex(index)) {
984 KFileItem* item = fileItem(index);
985 Q_ASSERT(item != 0);
986 if (item->isDir()) {
987 // the URLs are dropped above a directory
988 directory = item;
989 }
990 }
991
992 if ((directory == 0) && (source == itemView())) {
993 // The dropping is done into the same viewport where
994 // the dragging has been started. Just ignore this...
995 return;
996 }
997
998 const KUrl& destination = (directory == 0) ? url() :
999 directory->url();
1000 dropUrls(urls, destination);
1001 }
1002
1003 void DolphinView::dropUrls(const KUrl::List& urls,
1004 const KUrl& destination)
1005 {
1006 m_mainWindow->dropUrls(urls, destination);
1007 }
1008
1009 void DolphinView::updateSorting(DolphinView::Sorting sorting)
1010 {
1011 ViewProperties props(url());
1012 props.setSorting(sorting);
1013
1014 m_proxyModel->setSorting(sorting);
1015
1016 emit sortingChanged(sorting);
1017 }
1018
1019 void DolphinView::updateSortOrder(Qt::SortOrder order)
1020 {
1021 ViewProperties props(url());
1022 props.setSortOrder(order);
1023
1024 m_proxyModel->setSortOrder(order);
1025
1026 emit sortOrderChanged(order);
1027 }
1028
1029 void DolphinView::emitContentsMoved()
1030 {
1031 if (!m_blockContentsMovedSignal) {
1032 emit contentsMoved(contentsX(), contentsY());
1033 }
1034 }
1035
1036 void DolphinView::updateActivationState()
1037 {
1038 m_urlNavigator->setActive(isActive());
1039 if(isActive()) {
1040 emit urlChanged(url());
1041 emit selectionChanged(selectedItems());
1042 }
1043 }
1044
1045 void DolphinView::updateCutItems()
1046 {
1047 // restore the icons of all previously selected items to the
1048 // original state...
1049 QList<CutItem>::const_iterator it = m_cutItemsCache.begin();
1050 QList<CutItem>::const_iterator end = m_cutItemsCache.end();
1051 while (it != end) {
1052 const QModelIndex index = m_dirModel->indexForUrl((*it).url);
1053 if (index.isValid()) {
1054 m_dirModel->setData(index, QIcon((*it).pixmap), Qt::DecorationRole);
1055 }
1056 ++it;
1057 }
1058 m_cutItemsCache.clear();
1059
1060 // ... and apply an item effect to all currently cut items
1061 applyCutItemEffect();
1062 }
1063
1064 void DolphinView::createView()
1065 {
1066 // delete current view
1067 QAbstractItemView* view = itemView();
1068 if (view != 0) {
1069 m_topLayout->removeWidget(view);
1070 view->close();
1071 view->deleteLater();
1072 view = 0;
1073 m_iconsView = 0;
1074 m_detailsView = 0;
1075 m_fileItemDelegate = 0;
1076 }
1077
1078 Q_ASSERT(m_iconsView == 0);
1079 Q_ASSERT(m_detailsView == 0);
1080
1081 // ... and recreate it representing the current mode
1082 switch (m_mode) {
1083 case IconsView:
1084 m_iconsView = new DolphinIconsView(this, m_controller);
1085 view = m_iconsView;
1086 break;
1087
1088 case DetailsView:
1089 m_detailsView = new DolphinDetailsView(this, m_controller);
1090 view = m_detailsView;
1091 break;
1092 }
1093
1094 Q_ASSERT(view != 0);
1095
1096 m_fileItemDelegate = new KFileItemDelegate(view);
1097 view->setItemDelegate(m_fileItemDelegate);
1098
1099 view->setModel(m_proxyModel);
1100 view->setSelectionMode(QAbstractItemView::ExtendedSelection);
1101
1102 new KMimeTypeResolver(view, m_dirModel);
1103 m_topLayout->insertWidget(1, view);
1104
1105 connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
1106 m_controller, SLOT(indicateSelectionChange()));
1107 connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
1108 this, SLOT(emitContentsMoved()));
1109 connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)),
1110 this, SLOT(emitContentsMoved()));
1111 }
1112
1113 void DolphinView::selectAll(QItemSelectionModel::SelectionFlags flags)
1114 {
1115 QItemSelectionModel* selectionModel = itemView()->selectionModel();
1116 const QAbstractItemModel* itemModel = selectionModel->model();
1117
1118 const QModelIndex topLeft = itemModel->index(0, 0);
1119 const QModelIndex bottomRight = itemModel->index(itemModel->rowCount() - 1,
1120 itemModel->columnCount() - 1);
1121
1122 QItemSelection selection(topLeft, bottomRight);
1123 selectionModel->select(selection, flags);
1124 }
1125
1126 QAbstractItemView* DolphinView::itemView() const
1127 {
1128 Q_ASSERT((m_iconsView == 0) || (m_detailsView == 0));
1129 if (m_detailsView != 0) {
1130 return m_detailsView;
1131 }
1132 return m_iconsView;
1133 }
1134
1135 bool DolphinView::isValidNameIndex(const QModelIndex& index) const
1136 {
1137 return index.isValid() && (index.column() == KDirModel::Name);
1138 }
1139
1140 bool DolphinView::isCutItem(const KFileItem& item) const
1141 {
1142 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
1143 const KUrl::List cutUrls = KUrl::List::fromMimeData(mimeData);
1144
1145 const KUrl& itemUrl = item.url();
1146 KUrl::List::const_iterator it = cutUrls.begin();
1147 const KUrl::List::const_iterator end = cutUrls.end();
1148 while (it != end){
1149 if (*it == itemUrl) {
1150 return true;
1151 }
1152 ++it;
1153 }
1154
1155 return false;
1156 }
1157
1158 void DolphinView::applyCutItemEffect()
1159 {
1160 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
1161 if (!KonqMimeData::decodeIsCutSelection(mimeData)) {
1162 return;
1163 }
1164
1165 KFileItemList items(m_dirLister->items());
1166 KFileItemList::const_iterator it = items.begin();
1167 const KFileItemList::const_iterator end = items.end();
1168 while (it != end) {
1169 KFileItem* item = *it;
1170 if (isCutItem(*item)) {
1171 const QModelIndex index = m_dirModel->indexForItem(*item);
1172 const KFileItem* item = m_dirModel->itemForIndex(index);
1173 const QVariant value = m_dirModel->data(index, Qt::DecorationRole);
1174 if ((value.type() == QVariant::Icon) && (item != 0)) {
1175 const QIcon icon(qvariant_cast<QIcon>(value));
1176 QPixmap pixmap = icon.pixmap(128, 128);
1177
1178 // remember current pixmap for the item to be able
1179 // to restore it when other items get cut
1180 CutItem cutItem;
1181 cutItem.url = item->url();
1182 cutItem.pixmap = pixmap;
1183 m_cutItemsCache.append(cutItem);
1184
1185 // apply icon effect to the cut item
1186 KIconEffect iconEffect;
1187 pixmap = iconEffect.apply(pixmap, K3Icon::Desktop, K3Icon::DisabledState);
1188 m_dirModel->setData(index, QIcon(pixmap), Qt::DecorationRole);
1189 }
1190 }
1191 ++it;
1192 }
1193 }
1194
1195 #include "dolphinview.moc"