]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinview.cpp
Provide a setting to turn on/off tooltips. The tooltip implementation itself will...
[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 <QKeyEvent>
26 #include <QItemSelection>
27 #include <QBoxLayout>
28 #include <QTimer>
29 #include <QScrollBar>
30
31 #include <kactioncollection.h>
32 #include <kcolorscheme.h>
33 #include <kdirlister.h>
34 #include <kfileitemdelegate.h>
35 #include <kiconeffect.h>
36 #include <klocale.h>
37 #include <kio/deletejob.h>
38 #include <kio/netaccess.h>
39 #include <kio/previewjob.h>
40 #include <kjob.h>
41 #include <kmenu.h>
42 #include <kmessagebox.h>
43 #include <kmimetyperesolver.h>
44 #include <konq_operations.h>
45 #include <konqmimedata.h>
46 #include <ktoggleaction.h>
47 #include <kurl.h>
48
49 #include "dolphindropcontroller.h"
50 #include "dolphinmodel.h"
51 #include "dolphincolumnview.h"
52 #include "dolphincontroller.h"
53 #include "dolphinsortfilterproxymodel.h"
54 #include "dolphindetailsview.h"
55 #include "dolphiniconsview.h"
56 #include "dolphinsettings.h"
57 #include "dolphin_generalsettings.h"
58 #include "iconmanager.h"
59 #include "renamedialog.h"
60 #include "viewproperties.h"
61
62 DolphinView::DolphinView(QWidget* parent,
63 const KUrl& url,
64 KDirLister* dirLister,
65 DolphinModel* dolphinModel,
66 DolphinSortFilterProxyModel* proxyModel) :
67 QWidget(parent),
68 m_active(true),
69 m_showPreview(false),
70 m_loadingDirectory(false),
71 m_storedCategorizedSorting(false),
72 m_mode(DolphinView::IconsView),
73 m_topLayout(0),
74 m_controller(0),
75 m_iconsView(0),
76 m_detailsView(0),
77 m_columnView(0),
78 m_fileItemDelegate(0),
79 m_selectionModel(0),
80 m_dolphinModel(dolphinModel),
81 m_dirLister(dirLister),
82 m_proxyModel(proxyModel),
83 m_iconManager(0)
84 {
85 setFocusPolicy(Qt::StrongFocus);
86 m_topLayout = new QVBoxLayout(this);
87 m_topLayout->setSpacing(0);
88 m_topLayout->setMargin(0);
89
90 m_controller = new DolphinController(this);
91 m_controller->setUrl(url);
92
93 // Receiver of the DolphinView signal 'urlChanged()' don't need
94 // to care whether the internal controller changed the URL already or whether
95 // the controller just requested an URL change and will be updated later.
96 // In both cases the URL has been changed:
97 connect(m_controller, SIGNAL(urlChanged(const KUrl&)),
98 this, SIGNAL(urlChanged(const KUrl&)));
99 connect(m_controller, SIGNAL(requestUrlChange(const KUrl&)),
100 this, SIGNAL(urlChanged(const KUrl&)));
101
102 connect(m_controller, SIGNAL(requestContextMenu(const QPoint&)),
103 this, SLOT(openContextMenu(const QPoint&)));
104 connect(m_controller, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&, const KFileItem&)),
105 this, SLOT(dropUrls(const KUrl::List&, const KUrl&, const KFileItem&)));
106 connect(m_controller, SIGNAL(sortingChanged(DolphinView::Sorting)),
107 this, SLOT(updateSorting(DolphinView::Sorting)));
108 connect(m_controller, SIGNAL(sortOrderChanged(Qt::SortOrder)),
109 this, SLOT(updateSortOrder(Qt::SortOrder)));
110 connect(m_controller, SIGNAL(additionalInfoChanged(const KFileItemDelegate::InformationList&)),
111 this, SLOT(updateAdditionalInfo(const KFileItemDelegate::InformationList&)));
112 connect(m_controller, SIGNAL(itemTriggered(const KFileItem&)),
113 this, SLOT(triggerItem(const KFileItem&)));
114 connect(m_controller, SIGNAL(activated()),
115 this, SLOT(activate()));
116 connect(m_controller, SIGNAL(itemEntered(const KFileItem&)),
117 this, SLOT(showHoverInformation(const KFileItem&)));
118 connect(m_controller, SIGNAL(viewportEntered()),
119 this, SLOT(clearHoverInformation()));
120
121 applyViewProperties(url);
122 m_topLayout->addWidget(itemView());
123
124 if (DolphinSettings::instance().generalSettings()->showToolTips()) {
125 // TODO: instantiate ToolTipManager here...
126 }
127 }
128
129 DolphinView::~DolphinView()
130 {
131 }
132
133 const KUrl& DolphinView::url() const
134 {
135 return m_controller->url();
136 }
137
138 KUrl DolphinView::rootUrl() const
139 {
140 return isColumnViewActive() ? m_columnView->rootUrl() : url();
141 }
142
143 void DolphinView::setActive(bool active)
144 {
145 if (active == m_active) {
146 return;
147 }
148
149 m_active = active;
150 m_selectionModel->clearSelection();
151
152 QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
153 if (active) {
154 // TODO: emitting urlChanged() is a hack, as the URL hasn't really changed. It
155 // bypasses the problem when having a split view and changing the active view to
156 // update the some URL dependent states. A nicer approach should be no big deal...
157 emit urlChanged(url());
158 emit selectionChanged(selectedItems());
159 } else {
160 color.setAlpha(150);
161 }
162
163 QWidget* viewport = itemView()->viewport();
164 QPalette palette;
165 palette.setColor(viewport->backgroundRole(), color);
166 viewport->setPalette(palette);
167
168 update();
169
170 if (active) {
171 emit activated();
172 }
173
174 m_controller->indicateActivationChange(active);
175 }
176
177 bool DolphinView::isActive() const
178 {
179 return m_active;
180 }
181
182 void DolphinView::setMode(Mode mode)
183 {
184 if (mode == m_mode) {
185 return; // the wished mode is already set
186 }
187
188 m_mode = mode;
189
190 deleteView();
191
192 const KUrl viewPropsUrl = viewPropertiesUrl();
193 ViewProperties props(viewPropsUrl);
194 props.setViewMode(m_mode);
195 createView();
196
197 // the file item delegate has been recreated, apply the current
198 // additional information manually
199 const KFileItemDelegate::InformationList infoList = props.additionalInfo();
200 m_fileItemDelegate->setShowInformation(infoList);
201 emit additionalInfoChanged();
202
203 // Not all view modes support categorized sorting. Adjust the sorting model
204 // if changing the view mode results in a change of the categorized sorting
205 // capabilities.
206 m_storedCategorizedSorting = props.categorizedSorting();
207 const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting();
208 if (categorized != m_proxyModel->isCategorizedModel()) {
209 m_proxyModel->setCategorizedModel(categorized);
210 emit categorizedSortingChanged();
211 }
212
213 emit modeChanged();
214 }
215
216 DolphinView::Mode DolphinView::mode() const
217 {
218 return m_mode;
219 }
220
221 bool DolphinView::showPreview() const
222 {
223 return m_showPreview;
224 }
225
226 bool DolphinView::showHiddenFiles() const
227 {
228 return m_dirLister->showingDotFiles();
229 }
230
231 bool DolphinView::categorizedSorting() const
232 {
233 // If all view modes would support categorized sorting, returning
234 // m_proxyModel->isCategorizedModel() would be the way to go. As
235 // currently only the icons view supports caterized sorting, we remember
236 // the stored view properties state in m_storedCategorizedSorting and
237 // return this state. The application takes care to disable the corresponding
238 // checkbox by checking DolphinView::supportsCategorizedSorting() to indicate
239 // that this setting is not applied to the current view mode.
240 return m_storedCategorizedSorting;
241 }
242
243 bool DolphinView::supportsCategorizedSorting() const
244 {
245 return m_iconsView != 0;
246 }
247
248 void DolphinView::selectAll()
249 {
250 QAbstractItemView* view = itemView();
251 // TODO: there seems to be a bug in QAbstractItemView::selectAll(); if
252 // the Ctrl-key is pressed (e. g. for Ctrl+A), selectAll() inverts the
253 // selection instead of selecting all items. This is bypassed for KDE 4.0
254 // by invoking clearSelection() first.
255 view->clearSelection();
256 view->selectAll();
257 }
258
259 void DolphinView::invertSelection()
260 {
261 if (isColumnViewActive()) {
262 // QAbstractItemView does not offer a virtual method invertSelection()
263 // as counterpart to QAbstractItemView::selectAll(). This makes it
264 // necessary to delegate the inverting of the selection to the
265 // column view, as only the selection of the active column should
266 // get inverted.
267 m_columnView->invertSelection();
268 } else {
269 QItemSelectionModel* selectionModel = itemView()->selectionModel();
270 const QAbstractItemModel* itemModel = selectionModel->model();
271
272 const QModelIndex topLeft = itemModel->index(0, 0);
273 const QModelIndex bottomRight = itemModel->index(itemModel->rowCount() - 1,
274 itemModel->columnCount() - 1);
275
276 const QItemSelection selection(topLeft, bottomRight);
277 selectionModel->select(selection, QItemSelectionModel::Toggle);
278 }
279 }
280
281 bool DolphinView::hasSelection() const
282 {
283 return itemView()->selectionModel()->hasSelection();
284 }
285
286 void DolphinView::clearSelection()
287 {
288 itemView()->selectionModel()->clear();
289 }
290
291 KFileItemList DolphinView::selectedItems() const
292 {
293 const QAbstractItemView* view = itemView();
294
295 // Our view has a selection, we will map them back to the DolphinModel
296 // and then fill the KFileItemList.
297 Q_ASSERT((view != 0) && (view->selectionModel() != 0));
298
299 const QItemSelection selection = m_proxyModel->mapSelectionToSource(view->selectionModel()->selection());
300 KFileItemList itemList;
301
302 const QModelIndexList indexList = selection.indexes();
303 foreach (QModelIndex index, indexList) {
304 KFileItem item = m_dolphinModel->itemForIndex(index);
305 if (!item.isNull()) {
306 itemList.append(item);
307 }
308 }
309
310 return itemList;
311 }
312
313 KUrl::List DolphinView::selectedUrls() const
314 {
315 KUrl::List urls;
316 const KFileItemList list = selectedItems();
317 foreach (KFileItem item, list) {
318 urls.append(item.url());
319 }
320 return urls;
321 }
322
323 KFileItem DolphinView::fileItem(const QModelIndex& index) const
324 {
325 const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
326 return m_dolphinModel->itemForIndex(dolphinModelIndex);
327 }
328
329 void DolphinView::setContentsPosition(int x, int y)
330 {
331 QAbstractItemView* view = itemView();
332
333 // the ColumnView takes care itself for the horizontal scrolling
334 if (!isColumnViewActive()) {
335 view->horizontalScrollBar()->setValue(x);
336 }
337 view->verticalScrollBar()->setValue(y);
338
339 m_loadingDirectory = false;
340 }
341
342 QPoint DolphinView::contentsPosition() const
343 {
344 const int x = itemView()->horizontalScrollBar()->value();
345 const int y = itemView()->verticalScrollBar()->value();
346 return QPoint(x, y);
347 }
348
349 void DolphinView::zoomIn()
350 {
351 m_controller->triggerZoomIn();
352 m_iconManager->updatePreviews();
353 }
354
355 void DolphinView::zoomOut()
356 {
357 m_controller->triggerZoomOut();
358 m_iconManager->updatePreviews();
359 }
360
361 bool DolphinView::isZoomInPossible() const
362 {
363 return m_controller->isZoomInPossible();
364 }
365
366 bool DolphinView::isZoomOutPossible() const
367 {
368 return m_controller->isZoomOutPossible();
369 }
370
371 void DolphinView::setSorting(Sorting sorting)
372 {
373 if (sorting != this->sorting()) {
374 updateSorting(sorting);
375 }
376 }
377
378 DolphinView::Sorting DolphinView::sorting() const
379 {
380 return m_proxyModel->sorting();
381 }
382
383 void DolphinView::setSortOrder(Qt::SortOrder order)
384 {
385 if (sortOrder() != order) {
386 updateSortOrder(order);
387 }
388 }
389
390 Qt::SortOrder DolphinView::sortOrder() const
391 {
392 return m_proxyModel->sortOrder();
393 }
394
395 void DolphinView::setAdditionalInfo(KFileItemDelegate::InformationList info)
396 {
397 const KUrl viewPropsUrl = viewPropertiesUrl();
398 ViewProperties props(viewPropsUrl);
399 props.setAdditionalInfo(info);
400 m_fileItemDelegate->setShowInformation(info);
401
402 emit additionalInfoChanged();
403
404 if (itemView() != m_detailsView) {
405 // the details view requires no reloading of the directory, as it maps
406 // the file item delegate info to its columns internally
407 loadDirectory(viewPropsUrl);
408 }
409 }
410
411 KFileItemDelegate::InformationList DolphinView::additionalInfo() const
412 {
413 return m_fileItemDelegate->showInformation();
414 }
415
416 void DolphinView::reload()
417 {
418 setUrl(url());
419 loadDirectory(url(), true);
420 }
421
422 void DolphinView::refresh()
423 {
424 const bool oldActivationState = m_active;
425 m_active = true;
426
427 createView();
428 applyViewProperties(m_controller->url());
429 reload();
430
431 setActive(oldActivationState);
432 }
433
434 void DolphinView::updateView(const KUrl& url, const KUrl& rootUrl)
435 {
436 if (m_controller->url() == url) {
437 return;
438 }
439
440 m_controller->setUrl(url); // emits urlChanged, which we forward
441
442 if (!rootUrl.isEmpty() && rootUrl.isParentOf(url)) {
443 applyViewProperties(rootUrl);
444 loadDirectory(rootUrl);
445 if (itemView() == m_columnView) {
446 m_columnView->setRootUrl(rootUrl);
447 m_columnView->showColumn(url);
448 }
449 } else {
450 applyViewProperties(url);
451 loadDirectory(url);
452 }
453
454 emit startedPathLoading(url);
455 }
456
457 void DolphinView::setNameFilter(const QString& nameFilter)
458 {
459 m_proxyModel->setFilterRegExp(nameFilter);
460
461 if (isColumnViewActive()) {
462 // adjusting the directory lister is not enough in the case of the
463 // column view, as each column has its own directory lister internally...
464 m_columnView->setNameFilter(nameFilter);
465 }
466 }
467
468 void DolphinView::calculateItemCount(int& fileCount, int& folderCount)
469 {
470 foreach (KFileItem item, m_dirLister->items()) {
471 if (item.isDir()) {
472 ++folderCount;
473 } else {
474 ++fileCount;
475 }
476 }
477 }
478
479 void DolphinView::setUrl(const KUrl& url)
480 {
481 updateView(url, KUrl());
482 }
483
484 void DolphinView::changeSelection(const KFileItemList& selection)
485 {
486 clearSelection();
487 if (selection.isEmpty()) {
488 return;
489 }
490 const KUrl& baseUrl = url();
491 KUrl url;
492 QItemSelection new_selection;
493 foreach(const KFileItem& item, selection) {
494 url = item.url().upUrl();
495 if (baseUrl.equals(url, KUrl::CompareWithoutTrailingSlash)) {
496 QModelIndex index = m_proxyModel->mapFromSource(m_dolphinModel->indexForItem(item));
497 new_selection.select(index, index);
498 }
499 }
500 itemView()->selectionModel()->select(new_selection,
501 QItemSelectionModel::ClearAndSelect
502 | QItemSelectionModel::Current);
503 }
504
505 void DolphinView::renameSelectedItems()
506 {
507 const KFileItemList items = selectedItems();
508 if (items.count() > 1) {
509 // More than one item has been selected for renaming. Open
510 // a rename dialog and rename all items afterwards.
511 RenameDialog dialog(this, items);
512 if (dialog.exec() == QDialog::Rejected) {
513 return;
514 }
515
516 const QString newName = dialog.newName();
517 if (newName.isEmpty()) {
518 emit errorMessage(dialog.errorString());
519 } else {
520 // TODO: check how this can be integrated into KonqFileUndoManager/KonqOperations
521 // as one operation instead of n rename operations like it is done now...
522 Q_ASSERT(newName.contains('#'));
523
524 // iterate through all selected items and rename them...
525 int index = 1;
526 foreach (KFileItem item, items) {
527 const KUrl& oldUrl = item.url();
528 QString number;
529 number.setNum(index++);
530
531 QString name = newName;
532 name.replace('#', number);
533
534 if (oldUrl.fileName() != name) {
535 KUrl newUrl = oldUrl;
536 newUrl.setFileName(name);
537 KonqOperations::rename(this, oldUrl, newUrl);
538 emit doingOperation(KonqFileUndoManager::RENAME);
539 }
540 }
541 }
542 } else if (DolphinSettings::instance().generalSettings()->renameInline()) {
543 Q_ASSERT(items.count() == 1);
544
545 if (isColumnViewActive()) {
546 m_columnView->editItem(items.first());
547 } else {
548 const QModelIndex dirIndex = m_dolphinModel->indexForItem(items.first());
549 const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
550 itemView()->edit(proxyIndex);
551 }
552 } else {
553 Q_ASSERT(items.count() == 1);
554
555 RenameDialog dialog(this, items);
556 if (dialog.exec() == QDialog::Rejected) {
557 return;
558 }
559
560 const QString& newName = dialog.newName();
561 if (newName.isEmpty()) {
562 emit errorMessage(dialog.errorString());
563 } else {
564 const KUrl& oldUrl = items.first().url();
565 KUrl newUrl = oldUrl;
566 newUrl.setFileName(newName);
567 KonqOperations::rename(this, oldUrl, newUrl);
568 emit doingOperation(KonqFileUndoManager::RENAME);
569 }
570 }
571 }
572
573 void DolphinView::trashSelectedItems()
574 {
575 emit doingOperation(KonqFileUndoManager::TRASH);
576 KonqOperations::del(this, KonqOperations::TRASH, selectedUrls());
577 }
578
579 void DolphinView::deleteSelectedItems()
580 {
581 const KUrl::List list = selectedUrls();
582 const bool del = KonqOperations::askDeleteConfirmation(list,
583 KonqOperations::DEL,
584 KonqOperations::DEFAULT_CONFIRMATION,
585 this);
586
587 if (del) {
588 KIO::Job* job = KIO::del(list);
589 connect(job, SIGNAL(result(KJob*)),
590 this, SLOT(slotDeleteFileFinished(KJob*)));
591 }
592 }
593
594 void DolphinView::cutSelectedItems()
595 {
596 QMimeData* mimeData = new QMimeData();
597 const KUrl::List kdeUrls = selectedUrls();
598 const KUrl::List mostLocalUrls;
599 KonqMimeData::populateMimeData(mimeData, kdeUrls, mostLocalUrls, true);
600 QApplication::clipboard()->setMimeData(mimeData);
601 }
602
603 void DolphinView::copySelectedItems()
604 {
605 QMimeData* mimeData = new QMimeData();
606 const KUrl::List kdeUrls = selectedUrls();
607 const KUrl::List mostLocalUrls;
608 KonqMimeData::populateMimeData(mimeData, kdeUrls, mostLocalUrls, false);
609 QApplication::clipboard()->setMimeData(mimeData);
610 }
611
612 void DolphinView::paste()
613 {
614 pasteToUrl(url());
615 }
616
617 void DolphinView::pasteIntoFolder()
618 {
619 const KFileItemList items = selectedItems();
620 if ((items.count() == 1) && items.first().isDir()) {
621 pasteToUrl(items.first().url());
622 }
623 }
624
625 void DolphinView::setShowPreview(bool show)
626 {
627 if (m_showPreview == show) {
628 return;
629 }
630
631 const KUrl viewPropsUrl = viewPropertiesUrl();
632 ViewProperties props(viewPropsUrl);
633 props.setShowPreview(show);
634
635 m_showPreview = show;
636 m_iconManager->setShowPreview(show);
637 emit showPreviewChanged();
638
639 loadDirectory(viewPropsUrl);
640 }
641
642 void DolphinView::setShowHiddenFiles(bool show)
643 {
644 if (m_dirLister->showingDotFiles() == show) {
645 return;
646 }
647
648 const KUrl viewPropsUrl = viewPropertiesUrl();
649 ViewProperties props(viewPropsUrl);
650 props.setShowHiddenFiles(show);
651
652 m_dirLister->setShowingDotFiles(show);
653 emit showHiddenFilesChanged();
654
655 loadDirectory(viewPropsUrl);
656 }
657
658 void DolphinView::setCategorizedSorting(bool categorized)
659 {
660 if (categorized == categorizedSorting()) {
661 return;
662 }
663
664 // setCategorizedSorting(true) may only get invoked
665 // if the view supports categorized sorting
666 Q_ASSERT(!categorized || supportsCategorizedSorting());
667
668 ViewProperties props(viewPropertiesUrl());
669 props.setCategorizedSorting(categorized);
670 props.save();
671
672 m_storedCategorizedSorting = categorized;
673 m_proxyModel->setCategorizedModel(categorized);
674
675 emit categorizedSortingChanged();
676 }
677
678 void DolphinView::toggleSortOrder()
679 {
680 const Qt::SortOrder order = (sortOrder() == Qt::AscendingOrder) ?
681 Qt::DescendingOrder :
682 Qt::AscendingOrder;
683 setSortOrder(order);
684 }
685
686 void DolphinView::toggleAdditionalInfo(QAction* action)
687 {
688 const KFileItemDelegate::Information info =
689 static_cast<KFileItemDelegate::Information>(action->data().toInt());
690
691 KFileItemDelegate::InformationList list = additionalInfo();
692
693 const bool show = action->isChecked();
694
695 const int index = list.indexOf(info);
696 const bool containsInfo = (index >= 0);
697 if (show && !containsInfo) {
698 list.append(info);
699 setAdditionalInfo(list);
700 } else if (!show && containsInfo) {
701 list.removeAt(index);
702 setAdditionalInfo(list);
703 Q_ASSERT(list.indexOf(info) < 0);
704 }
705 }
706
707
708 void DolphinView::mouseReleaseEvent(QMouseEvent* event)
709 {
710 QWidget::mouseReleaseEvent(event);
711 setActive(true);
712 }
713
714 void DolphinView::wheelEvent(QWheelEvent* event)
715 {
716 if (event->modifiers() & Qt::ControlModifier) {
717 const int delta = event->delta();
718 if ((delta > 0) && isZoomInPossible()) {
719 zoomIn();
720 } else if ((delta < 0) && isZoomOutPossible()) {
721 zoomOut();
722 }
723 event->accept();
724 }
725 }
726
727 bool DolphinView::eventFilter(QObject* watched, QEvent* event)
728 {
729 if ((watched == itemView()) && (event->type() == QEvent::FocusIn)) {
730 m_controller->requestActivation();
731 }
732
733 return QWidget::eventFilter(watched, event);
734 }
735
736 void DolphinView::activate()
737 {
738 setActive(true);
739 }
740
741 void DolphinView::triggerItem(const KFileItem& item)
742 {
743 const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
744 if ((modifier & Qt::ShiftModifier) || (modifier & Qt::ControlModifier)) {
745 // items are selected by the user, hence don't trigger the
746 // item specified by 'index'
747 return;
748 }
749
750 if (item.isNull()) {
751 return;
752 }
753
754 emit itemTriggered(item); // caught by DolphinViewContainer or DolphinPart
755 }
756
757 void DolphinView::emitSelectionChangedSignal()
758 {
759 emit selectionChanged(DolphinView::selectedItems());
760 }
761
762 void DolphinView::openContextMenu(const QPoint& pos)
763 {
764 KFileItem item;
765
766 const QModelIndex index = itemView()->indexAt(pos);
767 if (index.isValid() && (index.column() == DolphinModel::Name)) {
768 item = fileItem(index);
769 }
770
771 emit requestContextMenu(item, url());
772 }
773
774 void DolphinView::dropUrls(const KUrl::List& urls,
775 const KUrl& destPath,
776 const KFileItem& destItem)
777 {
778 Q_ASSERT(!urls.isEmpty());
779 const KUrl& destination = !destItem.isNull() && destItem.isDir() ?
780 destItem.url() : destPath;
781 const KUrl sourceDir = KUrl(urls.first().directory());
782 if (sourceDir != destination) {
783 dropUrls(urls, destination);
784 }
785 }
786
787 void DolphinView::dropUrls(const KUrl::List& urls,
788 const KUrl& destination)
789 {
790 DolphinDropController dropController(this);
791 // forward doingOperation signal up to the mainwindow
792 connect(&dropController, SIGNAL(doingOperation(KonqFileUndoManager::CommandType)),
793 this, SIGNAL(doingOperation(KonqFileUndoManager::CommandType)));
794 dropController.dropUrls(urls, destination);
795 }
796
797 void DolphinView::updateSorting(DolphinView::Sorting sorting)
798 {
799 ViewProperties props(viewPropertiesUrl());
800 props.setSorting(sorting);
801
802 m_proxyModel->setSorting(sorting);
803
804 emit sortingChanged(sorting);
805 }
806
807 void DolphinView::updateSortOrder(Qt::SortOrder order)
808 {
809 ViewProperties props(viewPropertiesUrl());
810 props.setSortOrder(order);
811
812 m_proxyModel->setSortOrder(order);
813
814 emit sortOrderChanged(order);
815 }
816
817 void DolphinView::updateAdditionalInfo(const KFileItemDelegate::InformationList& info)
818 {
819 ViewProperties props(viewPropertiesUrl());
820 props.setAdditionalInfo(info);
821 props.save();
822
823 m_fileItemDelegate->setShowInformation(info);
824
825 emit additionalInfoChanged();
826 }
827
828 void DolphinView::updateAdditionalInfoActions(KActionCollection* collection)
829 {
830 const bool enable = (m_mode == DolphinView::DetailsView) ||
831 (m_mode == DolphinView::IconsView);
832
833 QAction* showSizeInfo = collection->action("show_size_info");
834 QAction* showDateInfo = collection->action("show_date_info");
835 QAction* showPermissionsInfo = collection->action("show_permissions_info");
836 QAction* showOwnerInfo = collection->action("show_owner_info");
837 QAction* showGroupInfo = collection->action("show_group_info");
838 QAction* showMimeInfo = collection->action("show_mime_info");
839
840 showSizeInfo->setChecked(false);
841 showDateInfo->setChecked(false);
842 showPermissionsInfo->setChecked(false);
843 showOwnerInfo->setChecked(false);
844 showGroupInfo->setChecked(false);
845 showMimeInfo->setChecked(false);
846
847 showSizeInfo->setEnabled(enable);
848 showDateInfo->setEnabled(enable);
849 showPermissionsInfo->setEnabled(enable);
850 showOwnerInfo->setEnabled(enable);
851 showGroupInfo->setEnabled(enable);
852 showMimeInfo->setEnabled(enable);
853
854 foreach (KFileItemDelegate::Information info, m_fileItemDelegate->showInformation()) {
855 switch (info) {
856 case KFileItemDelegate::Size:
857 showSizeInfo->setChecked(true);
858 break;
859 case KFileItemDelegate::ModificationTime:
860 showDateInfo->setChecked(true);
861 break;
862 case KFileItemDelegate::Permissions:
863 showPermissionsInfo->setChecked(true);
864 break;
865 case KFileItemDelegate::Owner:
866 showOwnerInfo->setChecked(true);
867 break;
868 case KFileItemDelegate::OwnerAndGroup:
869 showGroupInfo->setChecked(true);
870 break;
871 case KFileItemDelegate::FriendlyMimeType:
872 showMimeInfo->setChecked(true);
873 break;
874 default:
875 break;
876 }
877 }
878 }
879
880 QPair<bool, QString> DolphinView::pasteInfo() const
881 {
882 QPair<bool, QString> ret;
883 QClipboard* clipboard = QApplication::clipboard();
884 const QMimeData* mimeData = clipboard->mimeData();
885
886 KUrl::List urls = KUrl::List::fromMimeData(mimeData);
887 if (!urls.isEmpty()) {
888 ret.first = true;
889 if (urls.count() == 1) {
890 const KFileItem item(KFileItem::Unknown, KFileItem::Unknown, urls.first(), true);
891 ret.second = item.isDir() ? i18nc("@action:inmenu", "Paste One Folder") :
892 i18nc("@action:inmenu", "Paste One File");
893
894 } else {
895 ret.second = i18ncp("@action:inmenu", "Paste One Item", "Paste %1 Items", urls.count());
896 }
897 } else {
898 ret.first = false;
899 ret.second = i18nc("@action:inmenu", "Paste");
900 }
901
902 return ret;
903 }
904
905 void DolphinView::emitContentsMoved()
906 {
907 // only emit the contents moved signal if:
908 // - no directory loading is ongoing (this would reset the contents position
909 // always to (0, 0))
910 // - if the Column View is active: the column view does an automatic
911 // positioning during the loading operation, which must be remembered
912 if (!m_loadingDirectory || isColumnViewActive()) {
913 const QPoint pos(contentsPosition());
914 emit contentsMoved(pos.x(), pos.y());
915 }
916 }
917
918 void DolphinView::showHoverInformation(const KFileItem& item)
919 {
920 emit requestItemInfo(item);
921 }
922
923 void DolphinView::clearHoverInformation()
924 {
925 emit requestItemInfo(KFileItem());
926 }
927
928 void DolphinView::slotDeleteFileFinished(KJob* job)
929 {
930 if (job->error() == 0) {
931 emit operationCompletedMessage(i18nc("@info:status", "Delete operation completed."));
932 } else {
933 emit errorMessage(job->errorString());
934 }
935 }
936
937 void DolphinView::loadDirectory(const KUrl& url, bool reload)
938 {
939 if (!url.isValid()) {
940 const QString location(url.pathOrUrl());
941 if (location.isEmpty()) {
942 emit errorMessage(i18nc("@info:status", "The location is empty."));
943 } else {
944 emit errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location));
945 }
946 return;
947 }
948
949 m_loadingDirectory = true;
950
951 m_dirLister->stop();
952 m_dirLister->openUrl(url, reload ? KDirLister::Reload : KDirLister::NoFlags);
953
954 if (isColumnViewActive()) {
955 // adjusting the directory lister is not enough in the case of the
956 // column view, as each column has its own directory lister internally...
957 if (reload) {
958 m_columnView->reload();
959 } else {
960 m_columnView->showColumn(url);
961 }
962 }
963 }
964
965 KUrl DolphinView::viewPropertiesUrl() const
966 {
967 if (isColumnViewActive()) {
968 return m_columnView->rootUrl();
969 }
970
971 return url();
972 }
973
974 void DolphinView::applyViewProperties(const KUrl& url)
975 {
976 if (isColumnViewActive() && rootUrl().isParentOf(url)) {
977 // The column view is active, hence don't apply the view properties
978 // of sub directories (represented by columns) to the view. The
979 // view always represents the properties of the first column.
980 return;
981 }
982
983 const ViewProperties props(url);
984
985 const Mode mode = props.viewMode();
986 if (m_mode != mode) {
987 m_mode = mode;
988 createView();
989 emit modeChanged();
990 }
991 if (itemView() == 0) {
992 createView();
993 }
994 Q_ASSERT(itemView() != 0);
995 Q_ASSERT(m_fileItemDelegate != 0);
996
997 const bool showHiddenFiles = props.showHiddenFiles();
998 if (showHiddenFiles != m_dirLister->showingDotFiles()) {
999 m_dirLister->setShowingDotFiles(showHiddenFiles);
1000 emit showHiddenFilesChanged();
1001 }
1002
1003 m_storedCategorizedSorting = props.categorizedSorting();
1004 const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting();
1005 if (categorized != m_proxyModel->isCategorizedModel()) {
1006 m_proxyModel->setCategorizedModel(categorized);
1007 emit categorizedSortingChanged();
1008 }
1009
1010 const DolphinView::Sorting sorting = props.sorting();
1011 if (sorting != m_proxyModel->sorting()) {
1012 m_proxyModel->setSorting(sorting);
1013 emit sortingChanged(sorting);
1014 }
1015
1016 const Qt::SortOrder sortOrder = props.sortOrder();
1017 if (sortOrder != m_proxyModel->sortOrder()) {
1018 m_proxyModel->setSortOrder(sortOrder);
1019 emit sortOrderChanged(sortOrder);
1020 }
1021
1022 KFileItemDelegate::InformationList info = props.additionalInfo();
1023 if (info != m_fileItemDelegate->showInformation()) {
1024 m_fileItemDelegate->setShowInformation(info);
1025 emit additionalInfoChanged();
1026 }
1027
1028 const bool showPreview = props.showPreview();
1029 if (showPreview != m_showPreview) {
1030 m_showPreview = showPreview;
1031 m_iconManager->setShowPreview(showPreview);
1032 emit showPreviewChanged();
1033 }
1034 }
1035
1036 void DolphinView::createView()
1037 {
1038 deleteView();
1039 Q_ASSERT(m_iconsView == 0);
1040 Q_ASSERT(m_detailsView == 0);
1041 Q_ASSERT(m_columnView == 0);
1042
1043 QAbstractItemView* view = 0;
1044 switch (m_mode) {
1045 case IconsView: {
1046 m_iconsView = new DolphinIconsView(this, m_controller);
1047 view = m_iconsView;
1048 break;
1049 }
1050
1051 case DetailsView:
1052 m_detailsView = new DolphinDetailsView(this, m_controller);
1053 view = m_detailsView;
1054 break;
1055
1056 case ColumnView:
1057 m_columnView = new DolphinColumnView(this, m_controller);
1058 view = m_columnView;
1059 break;
1060 }
1061
1062 Q_ASSERT(view != 0);
1063 view->installEventFilter(this);
1064
1065 m_controller->setItemView(view);
1066
1067 m_fileItemDelegate = new KFileItemDelegate(view);
1068 view->setItemDelegate(m_fileItemDelegate);
1069
1070 view->setModel(m_proxyModel);
1071 if (m_selectionModel != 0) {
1072 view->setSelectionModel(m_selectionModel);
1073 } else {
1074 m_selectionModel = view->selectionModel();
1075 }
1076
1077 // reparent the selection model, as it should not be deleted
1078 // when deleting the model
1079 m_selectionModel->setParent(this);
1080
1081 view->setSelectionMode(QAbstractItemView::ExtendedSelection);
1082
1083 new KMimeTypeResolver(view, m_dolphinModel);
1084 m_iconManager = new IconManager(view, m_proxyModel);
1085 m_iconManager->setShowPreview(m_showPreview);
1086
1087 m_topLayout->insertWidget(1, view);
1088
1089 connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
1090 this, SLOT(emitSelectionChangedSignal()));
1091 connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
1092 this, SLOT(emitContentsMoved()));
1093 connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)),
1094 this, SLOT(emitContentsMoved()));
1095 }
1096
1097 void DolphinView::deleteView()
1098 {
1099 QAbstractItemView* view = itemView();
1100 if (view != 0) {
1101 m_topLayout->removeWidget(view);
1102 view->close();
1103 view->deleteLater();
1104 view = 0;
1105 m_iconsView = 0;
1106 m_detailsView = 0;
1107 m_columnView = 0;
1108 m_fileItemDelegate = 0;
1109 m_iconManager = 0;
1110 }
1111 }
1112
1113 QAbstractItemView* DolphinView::itemView() const
1114 {
1115 if (m_detailsView != 0) {
1116 return m_detailsView;
1117 } else if (m_columnView != 0) {
1118 return m_columnView;
1119 }
1120
1121 return m_iconsView;
1122 }
1123
1124 bool DolphinView::isCutItem(const KFileItem& item) const
1125 {
1126 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
1127 const KUrl::List cutUrls = KUrl::List::fromMimeData(mimeData);
1128
1129 const KUrl& itemUrl = item.url();
1130 KUrl::List::const_iterator it = cutUrls.begin();
1131 const KUrl::List::const_iterator end = cutUrls.end();
1132 while (it != end) {
1133 if (*it == itemUrl) {
1134 return true;
1135 }
1136 ++it;
1137 }
1138
1139 return false;
1140 }
1141
1142 void DolphinView::pasteToUrl(const KUrl& url)
1143 {
1144 QClipboard* clipboard = QApplication::clipboard();
1145 const QMimeData* mimeData = clipboard->mimeData();
1146
1147 const KUrl::List sourceUrls = KUrl::List::fromMimeData(mimeData);
1148 if (KonqMimeData::decodeIsCutSelection(mimeData)) {
1149 KonqOperations::copy(this, KonqOperations::MOVE, sourceUrls, url);
1150 emit doingOperation(KonqFileUndoManager::MOVE);
1151 clipboard->clear();
1152 } else {
1153 KonqOperations::copy(this, KonqOperations::COPY, sourceUrls, url);
1154 emit doingOperation(KonqFileUndoManager::COPY);
1155 }
1156 }
1157
1158 #include "dolphinview.moc"