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