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