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