]> cloud.milkyroute.net Git - dolphin.git/blob - src/views/dolphinview.cpp
Merge remote-tracking branch 'origin/KDE/4.10'
[dolphin.git] / src / views / dolphinview.cpp
1 /***************************************************************************
2 * Copyright (C) 2006-2009 by Peter Penz <peter.penz19@gmail.com> *
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 <config-nepomuk.h>
24
25 #include <QAbstractItemView>
26 #include <QApplication>
27 #include <QBoxLayout>
28 #include <QClipboard>
29 #include <QDropEvent>
30 #include <QGraphicsSceneDragDropEvent>
31 #include <QKeyEvent>
32 #include <QItemSelection>
33 #include <QTimer>
34 #include <QScrollBar>
35
36 #include <KActionCollection>
37 #include <KColorScheme>
38 #include <KDirModel>
39 #include <KIconEffect>
40 #include <KFileItem>
41 #include <KFileItemListProperties>
42 #include <KLocale>
43 #include <kitemviews/kfileitemmodel.h>
44 #include <kitemviews/kfileitemlistview.h>
45 #include <kitemviews/kitemlistcontainer.h>
46 #include <kitemviews/kitemlistheader.h>
47 #include <kitemviews/kitemlistselectionmanager.h>
48 #include <kitemviews/kitemlistview.h>
49 #include <kitemviews/kitemlistcontroller.h>
50 #include <KIO/DeleteJob>
51 #include <KIO/JobUiDelegate>
52 #include <KIO/NetAccess>
53 #include <KIO/PreviewJob>
54 #include <KJob>
55 #include <KMenu>
56 #include <KMessageBox>
57 #include <konq_fileitemcapabilities.h>
58 #include <konq_operations.h>
59 #include <konqmimedata.h>
60 #include <KToggleAction>
61 #include <KUrl>
62
63 #include "dolphinnewfilemenuobserver.h"
64 #include "dolphin_detailsmodesettings.h"
65 #include "dolphin_generalsettings.h"
66 #include "dolphinitemlistview.h"
67 #include "draganddrophelper.h"
68 #include "renamedialog.h"
69 #include "versioncontrol/versioncontrolobserver.h"
70 #include "viewmodecontroller.h"
71 #include "viewproperties.h"
72 #include "views/tooltips/tooltipmanager.h"
73 #include "zoomlevelinfo.h"
74
75 #ifdef HAVE_NEPOMUK
76 #include <Nepomuk2/ResourceManager>
77 #endif
78
79 namespace {
80 const int MaxModeEnum = DolphinView::CompactView;
81 };
82
83 DolphinView::DolphinView(const KUrl& url, QWidget* parent) :
84 QWidget(parent),
85 m_active(true),
86 m_tabsForFiles(false),
87 m_assureVisibleCurrentIndex(false),
88 m_isFolderWritable(true),
89 m_dragging(false),
90 m_url(url),
91 m_viewPropertiesContext(),
92 m_mode(DolphinView::IconsView),
93 m_visibleRoles(),
94 m_topLayout(0),
95 m_model(0),
96 m_view(0),
97 m_container(0),
98 m_toolTipManager(0),
99 m_selectionChangedTimer(0),
100 m_currentItemUrl(),
101 m_scrollToCurrentItem(false),
102 m_restoredContentsPosition(),
103 m_selectedUrls(),
104 m_clearSelectionBeforeSelectingNewItems(false),
105 m_markFirstNewlySelectedItemAsCurrent(false),
106 m_versionControlObserver(0)
107 {
108 m_topLayout = new QVBoxLayout(this);
109 m_topLayout->setSpacing(0);
110 m_topLayout->setMargin(0);
111
112 // When a new item has been created by the "Create New..." menu, the item should
113 // get selected and it must be assured that the item will get visible. As the
114 // creation is done asynchronously, several signals must be checked:
115 connect(&DolphinNewFileMenuObserver::instance(), SIGNAL(itemCreated(KUrl)),
116 this, SLOT(observeCreatedItem(KUrl)));
117
118 m_selectionChangedTimer = new QTimer(this);
119 m_selectionChangedTimer->setSingleShot(true);
120 m_selectionChangedTimer->setInterval(300);
121 connect(m_selectionChangedTimer, SIGNAL(timeout()),
122 this, SLOT(emitSelectionChangedSignal()));
123
124 m_model = new KFileItemModel(this);
125 m_view = new DolphinItemListView();
126 m_view->setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
127 m_view->setVisibleRoles(QList<QByteArray>() << "text");
128 applyModeToView();
129
130 KItemListController* controller = new KItemListController(m_model, m_view, this);
131 const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1;
132 controller->setAutoActivationDelay(delay);
133
134 // The EnlargeSmallPreviews setting can only be changed after the model
135 // has been set in the view by KItemListController.
136 m_view->setEnlargeSmallPreviews(GeneralSettings::enlargeSmallPreviews());
137
138 m_container = new KItemListContainer(controller, this);
139 m_container->installEventFilter(this);
140 setFocusProxy(m_container);
141 connect(m_container->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hideToolTip()));
142 connect(m_container->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hideToolTip()));
143
144 controller->setSelectionBehavior(KItemListController::MultiSelection);
145 connect(controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int)));
146 connect(controller, SIGNAL(itemsActivated(QSet<int>)), this, SLOT(slotItemsActivated(QSet<int>)));
147 connect(controller, SIGNAL(itemMiddleClicked(int)), this, SLOT(slotItemMiddleClicked(int)));
148 connect(controller, SIGNAL(itemContextMenuRequested(int,QPointF)), this, SLOT(slotItemContextMenuRequested(int,QPointF)));
149 connect(controller, SIGNAL(viewContextMenuRequested(QPointF)), this, SLOT(slotViewContextMenuRequested(QPointF)));
150 connect(controller, SIGNAL(headerContextMenuRequested(QPointF)), this, SLOT(slotHeaderContextMenuRequested(QPointF)));
151 connect(controller, SIGNAL(mouseButtonPressed(int,Qt::MouseButtons)), this, SLOT(slotMouseButtonPressed(int,Qt::MouseButtons)));
152 connect(controller, SIGNAL(itemHovered(int)), this, SLOT(slotItemHovered(int)));
153 connect(controller, SIGNAL(itemUnhovered(int)), this, SLOT(slotItemUnhovered(int)));
154 connect(controller, SIGNAL(itemDropEvent(int,QGraphicsSceneDragDropEvent*)), this, SLOT(slotItemDropEvent(int,QGraphicsSceneDragDropEvent*)));
155 connect(controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)), this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*)));
156
157 connect(m_model, SIGNAL(directoryLoadingStarted()), this, SLOT(slotDirectoryLoadingStarted()));
158 connect(m_model, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
159 connect(m_model, SIGNAL(directoryLoadingCanceled()), this, SIGNAL(directoryLoadingCanceled()));
160 connect(m_model, SIGNAL(directoryLoadingProgress(int)), this, SIGNAL(directoryLoadingProgress(int)));
161 connect(m_model, SIGNAL(directorySortingProgress(int)), this, SIGNAL(directorySortingProgress(int)));
162 connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
163 this, SLOT(slotItemsChanged()));
164 connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)), this, SIGNAL(itemCountChanged()));
165 connect(m_model, SIGNAL(itemsInserted(KItemRangeList)), this, SIGNAL(itemCountChanged()));
166 connect(m_model, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString)));
167 connect(m_model, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString)));
168 connect(m_model, SIGNAL(directoryRedirection(KUrl,KUrl)), this, SLOT(slotDirectoryRedirection(KUrl,KUrl)));
169 connect(m_model, SIGNAL(urlIsFileError(KUrl)), this, SIGNAL(urlIsFileError(KUrl)));
170
171 m_view->installEventFilter(this);
172 connect(m_view, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
173 this, SLOT(slotSortOrderChangedByHeader(Qt::SortOrder,Qt::SortOrder)));
174 connect(m_view, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
175 this, SLOT(slotSortRoleChangedByHeader(QByteArray,QByteArray)));
176 connect(m_view, SIGNAL(visibleRolesChanged(QList<QByteArray>,QList<QByteArray>)),
177 this, SLOT(slotVisibleRolesChangedByHeader(QList<QByteArray>,QList<QByteArray>)));
178 connect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
179 this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
180 connect(m_view->header(), SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)),
181 this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal)));
182
183 KItemListSelectionManager* selectionManager = controller->selectionManager();
184 connect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)),
185 this, SLOT(slotSelectionChanged(QSet<int>,QSet<int>)));
186
187 m_toolTipManager = new ToolTipManager(this);
188
189 m_versionControlObserver = new VersionControlObserver(this);
190 m_versionControlObserver->setModel(m_model);
191 connect(m_versionControlObserver, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString)));
192 connect(m_versionControlObserver, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString)));
193 connect(m_versionControlObserver, SIGNAL(operationCompletedMessage(QString)), this, SIGNAL(operationCompletedMessage(QString)));
194
195 applyViewProperties();
196 m_topLayout->addWidget(m_container);
197
198 loadDirectory(url);
199 }
200
201 DolphinView::~DolphinView()
202 {
203 }
204
205 KUrl DolphinView::url() const
206 {
207 return m_url;
208 }
209
210 void DolphinView::setActive(bool active)
211 {
212 if (active == m_active) {
213 return;
214 }
215
216 m_active = active;
217
218 QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
219 if (!active) {
220 color.setAlpha(150);
221 }
222
223 QWidget* viewport = m_container->viewport();
224 if (viewport) {
225 QPalette palette;
226 palette.setColor(viewport->backgroundRole(), color);
227 viewport->setPalette(palette);
228 }
229
230 update();
231
232 if (active) {
233 m_container->setFocus();
234 emit activated();
235 emit writeStateChanged(m_isFolderWritable);
236 }
237 }
238
239 bool DolphinView::isActive() const
240 {
241 return m_active;
242 }
243
244 void DolphinView::setMode(Mode mode)
245 {
246 if (mode != m_mode) {
247 ViewProperties props(viewPropertiesUrl());
248 props.setViewMode(mode);
249 props.save();
250
251 applyViewProperties();
252 }
253 }
254
255 DolphinView::Mode DolphinView::mode() const
256 {
257 return m_mode;
258 }
259
260 void DolphinView::setPreviewsShown(bool show)
261 {
262 if (previewsShown() == show) {
263 return;
264 }
265
266 ViewProperties props(viewPropertiesUrl());
267 props.setPreviewsShown(show);
268
269 const int oldZoomLevel = m_view->zoomLevel();
270 m_view->setPreviewsShown(show);
271 emit previewsShownChanged(show);
272
273 const int newZoomLevel = m_view->zoomLevel();
274 if (newZoomLevel != oldZoomLevel) {
275 emit zoomLevelChanged(newZoomLevel, oldZoomLevel);
276 }
277 }
278
279 bool DolphinView::previewsShown() const
280 {
281 return m_view->previewsShown();
282 }
283
284 void DolphinView::setHiddenFilesShown(bool show)
285 {
286 if (m_model->showHiddenFiles() == show) {
287 return;
288 }
289
290 const KFileItemList itemList = selectedItems();
291 m_selectedUrls.clear();
292 m_selectedUrls = itemList.urlList();
293
294 ViewProperties props(viewPropertiesUrl());
295 props.setHiddenFilesShown(show);
296
297 m_model->setShowHiddenFiles(show);
298 emit hiddenFilesShownChanged(show);
299 }
300
301 bool DolphinView::hiddenFilesShown() const
302 {
303 return m_model->showHiddenFiles();
304 }
305
306 void DolphinView::setGroupedSorting(bool grouped)
307 {
308 if (grouped == groupedSorting()) {
309 return;
310 }
311
312 ViewProperties props(viewPropertiesUrl());
313 props.setGroupedSorting(grouped);
314 props.save();
315
316 m_container->controller()->model()->setGroupedSorting(grouped);
317
318 emit groupedSortingChanged(grouped);
319 }
320
321 bool DolphinView::groupedSorting() const
322 {
323 return m_model->groupedSorting();
324 }
325
326 KFileItemList DolphinView::items() const
327 {
328 KFileItemList list;
329 const int itemCount = m_model->count();
330 list.reserve(itemCount);
331
332 for (int i = 0; i < itemCount; ++i) {
333 list.append(m_model->fileItem(i));
334 }
335
336 return list;
337 }
338
339 int DolphinView::itemsCount() const
340 {
341 return m_model->count();
342 }
343
344 KFileItemList DolphinView::selectedItems() const
345 {
346 const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
347 QList<int> selectedIndexes = selectionManager->selectedItems().toList();
348
349 qSort(selectedIndexes);
350
351 KFileItemList selectedItems;
352 QListIterator<int> it(selectedIndexes);
353 while (it.hasNext()) {
354 const int index = it.next();
355 selectedItems.append(m_model->fileItem(index));
356 }
357 return selectedItems;
358 }
359
360 int DolphinView::selectedItemsCount() const
361 {
362 const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
363 return selectionManager->selectedItems().count();
364 }
365
366 void DolphinView::markUrlsAsSelected(const QList<KUrl>& urls)
367 {
368 m_selectedUrls = urls;
369 }
370
371 void DolphinView::markUrlAsCurrent(const KUrl& url)
372 {
373 m_currentItemUrl = url;
374 m_scrollToCurrentItem = true;
375 }
376
377 void DolphinView::selectItems(const QRegExp& pattern, bool enabled)
378 {
379 const KItemListSelectionManager::SelectionMode mode = enabled
380 ? KItemListSelectionManager::Select
381 : KItemListSelectionManager::Deselect;
382 KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
383
384 for (int index = 0; index < m_model->count(); index++) {
385 const KFileItem item = m_model->fileItem(index);
386 if (pattern.exactMatch(item.text())) {
387 // An alternative approach would be to store the matching items in a QSet<int> and
388 // select them in one go after the loop, but we'd need a new function
389 // KItemListSelectionManager::setSelected(QSet<int>, SelectionMode mode)
390 // for that.
391 selectionManager->setSelected(index, 1, mode);
392 }
393 }
394 }
395
396 void DolphinView::setZoomLevel(int level)
397 {
398 const int oldZoomLevel = zoomLevel();
399 m_view->setZoomLevel(level);
400 if (zoomLevel() != oldZoomLevel) {
401 hideToolTip();
402 emit zoomLevelChanged(zoomLevel(), oldZoomLevel);
403 }
404 }
405
406 int DolphinView::zoomLevel() const
407 {
408 return m_view->zoomLevel();
409 }
410
411 void DolphinView::setSortRole(const QByteArray& role)
412 {
413 if (role != sortRole()) {
414 updateSortRole(role);
415 }
416 }
417
418 QByteArray DolphinView::sortRole() const
419 {
420 const KItemModelBase* model = m_container->controller()->model();
421 return model->sortRole();
422 }
423
424 void DolphinView::setSortOrder(Qt::SortOrder order)
425 {
426 if (sortOrder() != order) {
427 updateSortOrder(order);
428 }
429 }
430
431 Qt::SortOrder DolphinView::sortOrder() const
432 {
433 return m_model->sortOrder();
434 }
435
436 void DolphinView::setSortFoldersFirst(bool foldersFirst)
437 {
438 if (sortFoldersFirst() != foldersFirst) {
439 updateSortFoldersFirst(foldersFirst);
440 }
441 }
442
443 bool DolphinView::sortFoldersFirst() const
444 {
445 return m_model->sortDirectoriesFirst();
446 }
447
448 void DolphinView::setVisibleRoles(const QList<QByteArray>& roles)
449 {
450 const QList<QByteArray> previousRoles = roles;
451
452 ViewProperties props(viewPropertiesUrl());
453 props.setVisibleRoles(roles);
454
455 m_visibleRoles = roles;
456 m_view->setVisibleRoles(roles);
457
458 emit visibleRolesChanged(m_visibleRoles, previousRoles);
459 }
460
461 QList<QByteArray> DolphinView::visibleRoles() const
462 {
463 return m_visibleRoles;
464 }
465
466 void DolphinView::reload()
467 {
468 QByteArray viewState;
469 QDataStream saveStream(&viewState, QIODevice::WriteOnly);
470 saveState(saveStream);
471
472 const KFileItemList itemList = selectedItems();
473 m_selectedUrls.clear();
474 m_selectedUrls = itemList.urlList();
475
476 setUrl(url());
477 loadDirectory(url(), true);
478
479 QDataStream restoreStream(viewState);
480 restoreState(restoreStream);
481 }
482
483 void DolphinView::stopLoading()
484 {
485 m_model->cancelDirectoryLoading();
486 }
487
488 void DolphinView::readSettings()
489 {
490 const int oldZoomLevel = m_view->zoomLevel();
491
492 GeneralSettings::self()->readConfig();
493 m_view->readSettings();
494 applyViewProperties();
495
496 const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1;
497 m_container->controller()->setAutoActivationDelay(delay);
498
499 const int newZoomLevel = m_view->zoomLevel();
500 if (newZoomLevel != oldZoomLevel) {
501 emit zoomLevelChanged(newZoomLevel, oldZoomLevel);
502 }
503 }
504
505 void DolphinView::writeSettings()
506 {
507 GeneralSettings::self()->writeConfig();
508 m_view->writeSettings();
509 }
510
511 void DolphinView::setNameFilter(const QString& nameFilter)
512 {
513 m_model->setNameFilter(nameFilter);
514 }
515
516 QString DolphinView::nameFilter() const
517 {
518 return m_model->nameFilter();
519 }
520
521 void DolphinView::setMimeTypeFilters(const QStringList& filters)
522 {
523 return m_model->setMimeTypeFilters(filters);
524 }
525
526 QStringList DolphinView::mimeTypeFilters() const
527 {
528 return m_model->mimeTypeFilters();
529 }
530
531 QString DolphinView::statusBarText() const
532 {
533 QString summary;
534 QString foldersText;
535 QString filesText;
536
537 int folderCount = 0;
538 int fileCount = 0;
539 KIO::filesize_t totalFileSize = 0;
540
541 if (m_container->controller()->selectionManager()->hasSelection()) {
542 // Give a summary of the status of the selected files
543 const KFileItemList list = selectedItems();
544 foreach (const KFileItem& item, list) {
545 if (item.isDir()) {
546 ++folderCount;
547 } else {
548 ++fileCount;
549 totalFileSize += item.size();
550 }
551 }
552
553 if (folderCount + fileCount == 1) {
554 // If only one item is selected, show the filename
555 filesText = i18nc("@info:status", "<filename>%1</filename> selected", list.first().text());
556 } else {
557 // At least 2 items are selected
558 foldersText = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount);
559 filesText = i18ncp("@info:status", "1 File selected", "%1 Files selected", fileCount);
560 }
561 } else {
562 calculateItemCount(fileCount, folderCount, totalFileSize);
563 foldersText = i18ncp("@info:status", "1 Folder", "%1 Folders", folderCount);
564 filesText = i18ncp("@info:status", "1 File", "%1 Files", fileCount);
565 }
566
567 if (fileCount > 0 && folderCount > 0) {
568 summary = i18nc("@info:status folders, files (size)", "%1, %2 (%3)",
569 foldersText, filesText,
570 KGlobal::locale()->formatByteSize(totalFileSize));
571 } else if (fileCount > 0) {
572 summary = i18nc("@info:status files (size)", "%1 (%2)",
573 filesText,
574 KGlobal::locale()->formatByteSize(totalFileSize));
575 } else if (folderCount > 0) {
576 summary = foldersText;
577 } else {
578 summary = i18nc("@info:status", "0 Folders, 0 Files");
579 }
580
581 return summary;
582 }
583
584 QList<QAction*> DolphinView::versionControlActions(const KFileItemList& items) const
585 {
586 QList<QAction*> actions;
587
588 if (items.isEmpty()) {
589 const KFileItem item = m_model->rootItem();
590 if (!item.isNull()) {
591 actions = m_versionControlObserver->actions(KFileItemList() << item);
592 }
593 } else {
594 actions = m_versionControlObserver->actions(items);
595 }
596
597 return actions;
598 }
599
600 void DolphinView::setUrl(const KUrl& url)
601 {
602 if (url == m_url) {
603 return;
604 }
605
606 clearSelection();
607
608 emit urlAboutToBeChanged(url);
609 m_url = url;
610
611 hideToolTip();
612
613 // It is important to clear the items from the model before
614 // applying the view properties, otherwise expensive operations
615 // might be done on the existing items although they get cleared
616 // anyhow afterwards by loadDirectory().
617 m_model->clear();
618 applyViewProperties();
619 loadDirectory(url);
620
621 emit urlChanged(url);
622 }
623
624 void DolphinView::selectAll()
625 {
626 KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
627 selectionManager->setSelected(0, m_model->count());
628 }
629
630 void DolphinView::invertSelection()
631 {
632 KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
633 selectionManager->setSelected(0, m_model->count(), KItemListSelectionManager::Toggle);
634 }
635
636 void DolphinView::clearSelection()
637 {
638 m_selectedUrls.clear();
639 m_container->controller()->selectionManager()->clearSelection();
640 }
641
642 void DolphinView::renameSelectedItems()
643 {
644 const KFileItemList items = selectedItems();
645 if (items.isEmpty()) {
646 return;
647 }
648
649 if (items.count() == 1 && GeneralSettings::renameInline()) {
650 const int index = m_model->index(items.first());
651 m_view->editRole(index, "text");
652 } else {
653 RenameDialog* dialog = new RenameDialog(this, items);
654 dialog->setAttribute(Qt::WA_DeleteOnClose);
655 dialog->show();
656 dialog->raise();
657 dialog->activateWindow();
658 }
659
660 // Assure that the current index remains visible when KFileItemModel
661 // will notify the view about changed items (which might result in
662 // a changed sorting).
663 m_assureVisibleCurrentIndex = true;
664 }
665
666 void DolphinView::trashSelectedItems()
667 {
668 const KUrl::List list = simplifiedSelectedUrls();
669 KonqOperations::del(this, KonqOperations::TRASH, list);
670 }
671
672 void DolphinView::deleteSelectedItems()
673 {
674 const KUrl::List list = simplifiedSelectedUrls();
675 const bool del = KonqOperations::askDeleteConfirmation(list,
676 KonqOperations::DEL,
677 KonqOperations::DEFAULT_CONFIRMATION,
678 this);
679
680 if (del) {
681 KIO::Job* job = KIO::del(list);
682 if (job->ui()) {
683 job->ui()->setWindow(this);
684 }
685 connect(job, SIGNAL(result(KJob*)),
686 this, SLOT(slotDeleteFileFinished(KJob*)));
687 }
688 }
689
690 void DolphinView::cutSelectedItems()
691 {
692 QMimeData* mimeData = selectionMimeData();
693 KonqMimeData::addIsCutSelection(mimeData, true);
694 QApplication::clipboard()->setMimeData(mimeData);
695 }
696
697 void DolphinView::copySelectedItems()
698 {
699 QMimeData* mimeData = selectionMimeData();
700 QApplication::clipboard()->setMimeData(mimeData);
701 }
702
703 void DolphinView::paste()
704 {
705 pasteToUrl(url());
706 }
707
708 void DolphinView::pasteIntoFolder()
709 {
710 const KFileItemList items = selectedItems();
711 if ((items.count() == 1) && items.first().isDir()) {
712 pasteToUrl(items.first().url());
713 }
714 }
715
716 bool DolphinView::eventFilter(QObject* watched, QEvent* event)
717 {
718 switch (event->type()) {
719 case QEvent::FocusIn:
720 if (watched == m_container) {
721 setActive(true);
722 }
723 break;
724
725 case QEvent::GraphicsSceneDragEnter:
726 if (watched == m_view) {
727 m_dragging = true;
728 }
729 break;
730
731 case QEvent::GraphicsSceneDragLeave:
732 if (watched == m_view) {
733 m_dragging = false;
734 }
735 break;
736
737 case QEvent::GraphicsSceneDrop:
738 if (watched == m_view) {
739 m_dragging = false;
740 }
741 default:
742 break;
743 }
744
745 return QWidget::eventFilter(watched, event);
746 }
747
748 void DolphinView::wheelEvent(QWheelEvent* event)
749 {
750 if (event->modifiers().testFlag(Qt::ControlModifier)) {
751 const int numDegrees = event->delta() / 8;
752 const int numSteps = numDegrees / 15;
753
754 setZoomLevel(zoomLevel() + numSteps);
755 event->accept();
756 } else {
757 event->ignore();
758 }
759 }
760
761 void DolphinView::hideEvent(QHideEvent* event)
762 {
763 hideToolTip();
764 QWidget::hideEvent(event);
765 }
766
767 bool DolphinView::event(QEvent* event)
768 {
769 /* See Bug 297355
770 * Dolphin leaves file preview tooltips open even when is not visible.
771 *
772 * Hide tool-tip when Dolphin loses focus.
773 */
774 if (event->type() == QEvent::WindowDeactivate) {
775 hideToolTip();
776 }
777
778 return QWidget::event(event);
779 }
780
781 void DolphinView::activate()
782 {
783 setActive(true);
784 }
785
786 void DolphinView::slotItemActivated(int index)
787 {
788 const KFileItem item = m_model->fileItem(index);
789 if (!item.isNull()) {
790 emit itemActivated(item);
791 }
792 }
793
794 void DolphinView::slotItemsActivated(const QSet<int>& indexes)
795 {
796 Q_ASSERT(indexes.count() >= 2);
797
798 if (indexes.count() > 5) {
799 QString question = i18np("Are you sure you want to open 1 item?", "Are you sure you want to open %1 items?", indexes.count());
800 const int answer = KMessageBox::warningYesNo(this, question);
801 if (answer != KMessageBox::Yes) {
802 return;
803 }
804 }
805
806 KFileItemList items;
807 items.reserve(indexes.count());
808
809 QSetIterator<int> it(indexes);
810 while (it.hasNext()) {
811 const int index = it.next();
812 KFileItem item = m_model->fileItem(index);
813
814 if (item.isDir()) { // Open folders in new tabs
815 emit tabRequested(item.url());
816 } else {
817 items.append(item);
818 }
819 }
820
821 if (items.count() == 1) {
822 emit itemActivated(items.first());
823 } else if (items.count() > 1) {
824 emit itemsActivated(items);
825 }
826 }
827
828 void DolphinView::slotItemMiddleClicked(int index)
829 {
830 const KFileItem item = m_model->fileItem(index);
831 if (item.isDir() || isTabsForFilesEnabled()) {
832 emit tabRequested(item.url());
833 }
834 }
835
836 void DolphinView::slotItemContextMenuRequested(int index, const QPointF& pos)
837 {
838 const KFileItem item = m_model->fileItem(index);
839 emit requestContextMenu(pos.toPoint(), item, url(), QList<QAction*>());
840 }
841
842 void DolphinView::slotViewContextMenuRequested(const QPointF& pos)
843 {
844 emit requestContextMenu(pos.toPoint(), KFileItem(), url(), QList<QAction*>());
845 }
846
847 void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos)
848 {
849 ViewProperties props(viewPropertiesUrl());
850
851 QPointer<KMenu> menu = new KMenu(QApplication::activeWindow());
852
853 KItemListView* view = m_container->controller()->view();
854 const QSet<QByteArray> visibleRolesSet = view->visibleRoles().toSet();
855
856 bool nepomukRunning = false;
857 bool indexingEnabled = false;
858 #ifdef HAVE_NEPOMUK
859 nepomukRunning = (Nepomuk2::ResourceManager::instance()->initialized());
860 if (nepomukRunning) {
861 KConfig config("nepomukserverrc");
862 indexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", true);
863 }
864 #endif
865
866 QString groupName;
867 QMenu* groupMenu = 0;
868
869 // Add all roles to the menu that can be shown or hidden by the user
870 const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation();
871 foreach (const KFileItemModel::RoleInfo& info, rolesInfo) {
872 if (info.role == "text") {
873 // It should not be possible to hide the "text" role
874 continue;
875 }
876
877 const QString text = m_model->roleDescription(info.role);
878 QAction* action = 0;
879 if (info.group.isEmpty()) {
880 action = menu->addAction(text);
881 } else {
882 if (!groupMenu || info.group != groupName) {
883 groupName = info.group;
884 groupMenu = menu->addMenu(groupName);
885 }
886
887 action = groupMenu->addAction(text);
888 }
889
890 action->setCheckable(true);
891 action->setChecked(visibleRolesSet.contains(info.role));
892 action->setData(info.role);
893
894 const bool enable = (!info.requiresNepomuk && !info.requiresIndexer) ||
895 (info.requiresNepomuk && nepomukRunning) ||
896 (info.requiresIndexer && indexingEnabled);
897 action->setEnabled(enable);
898 }
899
900 menu->addSeparator();
901
902 QActionGroup* widthsGroup = new QActionGroup(menu);
903 const bool autoColumnWidths = props.headerColumnWidths().isEmpty();
904
905 QAction* autoAdjustWidthsAction = menu->addAction(i18nc("@action:inmenu", "Automatic Column Widths"));
906 autoAdjustWidthsAction->setCheckable(true);
907 autoAdjustWidthsAction->setChecked(autoColumnWidths);
908 autoAdjustWidthsAction->setActionGroup(widthsGroup);
909
910 QAction* customWidthsAction = menu->addAction(i18nc("@action:inmenu", "Custom Column Widths"));
911 customWidthsAction->setCheckable(true);
912 customWidthsAction->setChecked(!autoColumnWidths);
913 customWidthsAction->setActionGroup(widthsGroup);
914
915 QAction* action = menu->exec(pos.toPoint());
916 if (menu && action) {
917 KItemListHeader* header = view->header();
918
919 if (action == autoAdjustWidthsAction) {
920 // Clear the column-widths from the viewproperties and turn on
921 // the automatic resizing of the columns
922 props.setHeaderColumnWidths(QList<int>());
923 header->setAutomaticColumnResizing(true);
924 } else if (action == customWidthsAction) {
925 // Apply the current column-widths as custom column-widths and turn
926 // off the automatic resizing of the columns
927 QList<int> columnWidths;
928 foreach (const QByteArray& role, view->visibleRoles()) {
929 columnWidths.append(header->columnWidth(role));
930 }
931 props.setHeaderColumnWidths(columnWidths);
932 header->setAutomaticColumnResizing(false);
933 } else {
934 // Show or hide the selected role
935 const QByteArray selectedRole = action->data().toByteArray();
936
937 QList<QByteArray> visibleRoles = view->visibleRoles();
938 if (action->isChecked()) {
939 visibleRoles.append(selectedRole);
940 } else {
941 visibleRoles.removeOne(selectedRole);
942 }
943
944 view->setVisibleRoles(visibleRoles);
945 props.setVisibleRoles(visibleRoles);
946
947 QList<int> columnWidths;
948 if (!header->automaticColumnResizing()) {
949 foreach (const QByteArray& role, view->visibleRoles()) {
950 columnWidths.append(header->columnWidth(role));
951 }
952 }
953 props.setHeaderColumnWidths(columnWidths);
954 }
955 }
956
957 delete menu;
958 }
959
960 void DolphinView::slotHeaderColumnWidthChanged(const QByteArray& role, qreal current, qreal previous)
961 {
962 Q_UNUSED(previous);
963
964 const QList<QByteArray> visibleRoles = m_view->visibleRoles();
965
966 ViewProperties props(viewPropertiesUrl());
967 QList<int> columnWidths = props.headerColumnWidths();
968 if (columnWidths.count() != visibleRoles.count()) {
969 columnWidths.clear();
970 columnWidths.reserve(visibleRoles.count());
971 const KItemListHeader* header = m_view->header();
972 foreach (const QByteArray& role, visibleRoles) {
973 const int width = header->columnWidth(role);
974 columnWidths.append(width);
975 }
976 }
977
978 const int roleIndex = visibleRoles.indexOf(role);
979 Q_ASSERT(roleIndex >= 0 && roleIndex < columnWidths.count());
980 columnWidths[roleIndex] = current;
981
982 props.setHeaderColumnWidths(columnWidths);
983 }
984
985 void DolphinView::slotItemHovered(int index)
986 {
987 const KFileItem item = m_model->fileItem(index);
988
989 if (GeneralSettings::showToolTips() && !m_dragging) {
990 QRectF itemRect = m_container->controller()->view()->itemContextRect(index);
991 const QPoint pos = m_container->mapToGlobal(itemRect.topLeft().toPoint());
992 itemRect.moveTo(pos);
993
994 m_toolTipManager->showToolTip(item, itemRect);
995 }
996
997 emit requestItemInfo(item);
998 }
999
1000 void DolphinView::slotItemUnhovered(int index)
1001 {
1002 Q_UNUSED(index);
1003 hideToolTip();
1004 emit requestItemInfo(KFileItem());
1005 }
1006
1007 void DolphinView::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
1008 {
1009 KUrl destUrl;
1010 KFileItem destItem = m_model->fileItem(index);
1011 if (destItem.isNull() || (!destItem.isDir() && !destItem.isDesktopFile())) {
1012 // Use the URL of the view as drop target if the item is no directory
1013 // or desktop-file
1014 destItem = m_model->rootItem();
1015 destUrl = url();
1016 } else {
1017 // The item represents a directory or desktop-file
1018 destUrl = destItem.url();
1019 }
1020
1021 QDropEvent dropEvent(event->pos().toPoint(),
1022 event->possibleActions(),
1023 event->mimeData(),
1024 event->buttons(),
1025 event->modifiers());
1026
1027 QString error;
1028 KonqOperations* op = DragAndDropHelper::dropUrls(destItem, destUrl, &dropEvent, error);
1029 if (!error.isEmpty()) {
1030 emit infoMessage(error);
1031 }
1032
1033 if (op && destUrl == url()) {
1034 // Mark the dropped urls as selected.
1035 m_clearSelectionBeforeSelectingNewItems = true;
1036 connect(op, SIGNAL(urlPasted(KUrl)), this, SLOT(slotUrlPasted(KUrl)));
1037 }
1038 }
1039
1040 void DolphinView::slotModelChanged(KItemModelBase* current, KItemModelBase* previous)
1041 {
1042 if (previous != 0) {
1043 disconnect(previous, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
1044 m_versionControlObserver->setModel(0);
1045 }
1046
1047 if (current) {
1048 Q_ASSERT(qobject_cast<KFileItemModel*>(current));
1049 connect(current, SIGNAL(loadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
1050
1051 KFileItemModel* fileItemModel = static_cast<KFileItemModel*>(current);
1052 m_versionControlObserver->setModel(fileItemModel);
1053 }
1054 }
1055
1056 void DolphinView::slotMouseButtonPressed(int itemIndex, Qt::MouseButtons buttons)
1057 {
1058 hideToolTip();
1059
1060 if (itemIndex < 0) {
1061 // Trigger the history navigation only when clicking on the viewport:
1062 // Above an item the XButtons provide a simple way to select items in
1063 // the singleClick mode.
1064 if (buttons & Qt::XButton1) {
1065 emit goBackRequested();
1066 } else if (buttons & Qt::XButton2) {
1067 emit goForwardRequested();
1068 }
1069 }
1070 }
1071
1072 void DolphinView::slotAboutToCreate(const KUrl::List& urls)
1073 {
1074 if (!urls.isEmpty()) {
1075 if (m_markFirstNewlySelectedItemAsCurrent) {
1076 markUrlAsCurrent(urls.first());
1077 m_markFirstNewlySelectedItemAsCurrent = false;
1078 }
1079 m_selectedUrls << urls;
1080 }
1081 }
1082
1083 void DolphinView::slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous)
1084 {
1085 const int currentCount = current.count();
1086 const int previousCount = previous.count();
1087 const bool selectionStateChanged = (currentCount == 0 && previousCount > 0) ||
1088 (currentCount > 0 && previousCount == 0);
1089
1090 // If nothing has been selected before and something got selected (or if something
1091 // was selected before and now nothing is selected) the selectionChangedSignal must
1092 // be emitted asynchronously as fast as possible to update the edit-actions.
1093 m_selectionChangedTimer->setInterval(selectionStateChanged ? 0 : 300);
1094 m_selectionChangedTimer->start();
1095 }
1096
1097 void DolphinView::emitSelectionChangedSignal()
1098 {
1099 m_selectionChangedTimer->stop();
1100 emit selectionChanged(selectedItems());
1101 }
1102
1103 void DolphinView::updateSortRole(const QByteArray& role)
1104 {
1105 ViewProperties props(viewPropertiesUrl());
1106 props.setSortRole(role);
1107
1108 KItemModelBase* model = m_container->controller()->model();
1109 model->setSortRole(role);
1110
1111 emit sortRoleChanged(role);
1112 }
1113
1114 void DolphinView::updateSortOrder(Qt::SortOrder order)
1115 {
1116 ViewProperties props(viewPropertiesUrl());
1117 props.setSortOrder(order);
1118
1119 m_model->setSortOrder(order);
1120
1121 emit sortOrderChanged(order);
1122 }
1123
1124 void DolphinView::updateSortFoldersFirst(bool foldersFirst)
1125 {
1126 ViewProperties props(viewPropertiesUrl());
1127 props.setSortFoldersFirst(foldersFirst);
1128
1129 m_model->setSortDirectoriesFirst(foldersFirst);
1130
1131 emit sortFoldersFirstChanged(foldersFirst);
1132 }
1133
1134 QPair<bool, QString> DolphinView::pasteInfo() const
1135 {
1136 return KonqOperations::pasteInfo(url());
1137 }
1138
1139 void DolphinView::setTabsForFilesEnabled(bool tabsForFiles)
1140 {
1141 m_tabsForFiles = tabsForFiles;
1142 }
1143
1144 bool DolphinView::isTabsForFilesEnabled() const
1145 {
1146 return m_tabsForFiles;
1147 }
1148
1149 bool DolphinView::itemsExpandable() const
1150 {
1151 return m_mode == DetailsView;
1152 }
1153
1154 void DolphinView::restoreState(QDataStream& stream)
1155 {
1156 // Restore the current item that had the keyboard focus
1157 stream >> m_currentItemUrl;
1158
1159 // Restore the view position
1160 stream >> m_restoredContentsPosition;
1161
1162 // Restore expanded folders (only relevant for the details view - will be ignored by the view in other view modes)
1163 QSet<KUrl> urls;
1164 stream >> urls;
1165 m_model->restoreExpandedDirectories(urls);
1166 }
1167
1168 void DolphinView::saveState(QDataStream& stream)
1169 {
1170 // Save the current item that has the keyboard focus
1171 const int currentIndex = m_container->controller()->selectionManager()->currentItem();
1172 if (currentIndex != -1) {
1173 KFileItem item = m_model->fileItem(currentIndex);
1174 Q_ASSERT(!item.isNull()); // If the current index is valid a item must exist
1175 KUrl currentItemUrl = item.url();
1176 stream << currentItemUrl;
1177 } else {
1178 stream << KUrl();
1179 }
1180
1181 // Save view position
1182 const qreal x = m_container->horizontalScrollBar()->value();
1183 const qreal y = m_container->verticalScrollBar()->value();
1184 stream << QPoint(x, y);
1185
1186 // Save expanded folders (only relevant for the details view - the set will be empty in other view modes)
1187 stream << m_model->expandedDirectories();
1188 }
1189
1190 KFileItem DolphinView::rootItem() const
1191 {
1192 return m_model->rootItem();
1193 }
1194
1195 void DolphinView::setViewPropertiesContext(const QString& context)
1196 {
1197 m_viewPropertiesContext = context;
1198 }
1199
1200 QString DolphinView::viewPropertiesContext() const
1201 {
1202 return m_viewPropertiesContext;
1203 }
1204
1205 void DolphinView::observeCreatedItem(const KUrl& url)
1206 {
1207 if (m_active) {
1208 clearSelection();
1209 markUrlAsCurrent(url);
1210 markUrlsAsSelected(QList<KUrl>() << url);
1211 }
1212 }
1213
1214 void DolphinView::slotDirectoryRedirection(const KUrl& oldUrl, const KUrl& newUrl)
1215 {
1216 if (oldUrl.equals(url(), KUrl::CompareWithoutTrailingSlash)) {
1217 emit redirection(oldUrl, newUrl);
1218 m_url = newUrl; // #186947
1219 }
1220 }
1221
1222 void DolphinView::updateViewState()
1223 {
1224 if (m_currentItemUrl != KUrl()) {
1225 KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
1226 const int currentIndex = m_model->index(m_currentItemUrl);
1227 if (currentIndex != -1) {
1228 selectionManager->setCurrentItem(currentIndex);
1229
1230 // scroll to current item and reset the state
1231 if (m_scrollToCurrentItem) {
1232 m_view->scrollToItem(currentIndex);
1233 m_scrollToCurrentItem = false;
1234 }
1235
1236 m_currentItemUrl = KUrl();
1237 } else {
1238 selectionManager->setCurrentItem(0);
1239 }
1240 }
1241
1242 if (!m_restoredContentsPosition.isNull()) {
1243 const int x = m_restoredContentsPosition.x();
1244 const int y = m_restoredContentsPosition.y();
1245 m_restoredContentsPosition = QPoint();
1246
1247 m_container->horizontalScrollBar()->setValue(x);
1248 m_container->verticalScrollBar()->setValue(y);
1249 }
1250
1251 if (!m_selectedUrls.isEmpty()) {
1252 KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
1253
1254 if (m_clearSelectionBeforeSelectingNewItems) {
1255 selectionManager->clearSelection();
1256 m_clearSelectionBeforeSelectingNewItems = false;
1257 }
1258
1259 QSet<int> selectedItems = selectionManager->selectedItems();
1260
1261 QList<KUrl>::iterator it = m_selectedUrls.begin();
1262 while (it != m_selectedUrls.end()) {
1263 const int index = m_model->index(*it);
1264 if (index >= 0) {
1265 selectedItems.insert(index);
1266 it = m_selectedUrls.erase(it);
1267 } else {
1268 ++it;
1269 }
1270 }
1271
1272 selectionManager->setSelectedItems(selectedItems);
1273 }
1274 }
1275
1276 void DolphinView::hideToolTip()
1277 {
1278 if (GeneralSettings::showToolTips()) {
1279 m_toolTipManager->hideToolTip();
1280 }
1281 }
1282
1283 void DolphinView::calculateItemCount(int& fileCount,
1284 int& folderCount,
1285 KIO::filesize_t& totalFileSize) const
1286 {
1287 const int itemCount = m_model->count();
1288 for (int i = 0; i < itemCount; ++i) {
1289 const KFileItem item = m_model->fileItem(i);
1290 if (item.isDir()) {
1291 ++folderCount;
1292 } else {
1293 ++fileCount;
1294 totalFileSize += item.size();
1295 }
1296 }
1297 }
1298
1299 void DolphinView::showHoverInformation(const KFileItem& item)
1300 {
1301 emit requestItemInfo(item);
1302 }
1303
1304 void DolphinView::clearHoverInformation()
1305 {
1306 emit requestItemInfo(KFileItem());
1307 }
1308
1309 void DolphinView::slotDeleteFileFinished(KJob* job)
1310 {
1311 if (job->error() == 0) {
1312 emit operationCompletedMessage(i18nc("@info:status", "Delete operation completed."));
1313 } else if (job->error() != KIO::ERR_USER_CANCELED) {
1314 emit errorMessage(job->errorString());
1315 }
1316 }
1317
1318 void DolphinView::slotDirectoryLoadingStarted()
1319 {
1320 // Disable the writestate temporary until it can be determined in a fast way
1321 // in DolphinView::slotLoadingCompleted()
1322 if (m_isFolderWritable) {
1323 m_isFolderWritable = false;
1324 emit writeStateChanged(m_isFolderWritable);
1325 }
1326
1327 emit directoryLoadingStarted();
1328 }
1329
1330 void DolphinView::slotDirectoryLoadingCompleted()
1331 {
1332 // Update the view-state. This has to be done asynchronously
1333 // because the view might not be in its final state yet.
1334 QTimer::singleShot(0, this, SLOT(updateViewState()));
1335
1336 emit directoryLoadingCompleted();
1337
1338 updateWritableState();
1339 }
1340
1341 void DolphinView::slotItemsChanged()
1342 {
1343 m_assureVisibleCurrentIndex = false;
1344 }
1345
1346 void DolphinView::slotSortOrderChangedByHeader(Qt::SortOrder current, Qt::SortOrder previous)
1347 {
1348 Q_UNUSED(previous);
1349 Q_ASSERT(m_model->sortOrder() == current);
1350
1351 ViewProperties props(viewPropertiesUrl());
1352 props.setSortOrder(current);
1353
1354 emit sortOrderChanged(current);
1355 }
1356
1357 void DolphinView::slotSortRoleChangedByHeader(const QByteArray& current, const QByteArray& previous)
1358 {
1359 Q_UNUSED(previous);
1360 Q_ASSERT(m_model->sortRole() == current);
1361
1362 ViewProperties props(viewPropertiesUrl());
1363 props.setSortRole(current);
1364
1365 emit sortRoleChanged(current);
1366 }
1367
1368 void DolphinView::slotVisibleRolesChangedByHeader(const QList<QByteArray>& current,
1369 const QList<QByteArray>& previous)
1370 {
1371 Q_UNUSED(previous);
1372 Q_ASSERT(m_container->controller()->view()->visibleRoles() == current);
1373
1374 const QList<QByteArray> previousVisibleRoles = m_visibleRoles;
1375
1376 m_visibleRoles = current;
1377
1378 ViewProperties props(viewPropertiesUrl());
1379 props.setVisibleRoles(m_visibleRoles);
1380
1381 emit visibleRolesChanged(m_visibleRoles, previousVisibleRoles);
1382 }
1383
1384 void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value)
1385 {
1386 if (index < 0 || index >= m_model->count()) {
1387 return;
1388 }
1389
1390 if (role == "text") {
1391 const KFileItem oldItem = m_model->fileItem(index);
1392 const QString newName = value.toString();
1393 if (!newName.isEmpty() && newName != oldItem.text() && newName != QLatin1String(".") && newName != QLatin1String("..")) {
1394 const KUrl oldUrl = oldItem.url();
1395
1396 const KUrl newUrl(url().path(KUrl::AddTrailingSlash) + newName);
1397 const bool newNameExistsAlready = (m_model->index(newUrl) >= 0);
1398 if (!newNameExistsAlready) {
1399 // Only change the data in the model if no item with the new name
1400 // is in the model yet. If there is an item with the new name
1401 // already, calling KonqOperations::rename() will open a dialog
1402 // asking for a new name, and KFileItemModel will update the
1403 // data when the dir lister signals that the file name has changed.
1404 QHash<QByteArray, QVariant> data;
1405 data.insert(role, value);
1406 m_model->setData(index, data);
1407 }
1408
1409 KonqOperations::rename(this, oldUrl, newName);
1410 }
1411 }
1412 }
1413
1414 void DolphinView::loadDirectory(const KUrl& url, bool reload)
1415 {
1416 if (!url.isValid()) {
1417 const QString location(url.pathOrUrl());
1418 if (location.isEmpty()) {
1419 emit errorMessage(i18nc("@info:status", "The location is empty."));
1420 } else {
1421 emit errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location));
1422 }
1423 return;
1424 }
1425
1426 if (reload) {
1427 m_model->refreshDirectory(url);
1428 } else {
1429 m_model->loadDirectory(url);
1430 }
1431 }
1432
1433 void DolphinView::applyViewProperties()
1434 {
1435 m_view->beginTransaction();
1436
1437 const ViewProperties props(viewPropertiesUrl());
1438
1439 const Mode mode = props.viewMode();
1440 if (m_mode != mode) {
1441 const Mode previousMode = m_mode;
1442 m_mode = mode;
1443
1444 // Changing the mode might result in changing
1445 // the zoom level. Remember the old zoom level so
1446 // that zoomLevelChanged() can get emitted.
1447 const int oldZoomLevel = m_view->zoomLevel();
1448 applyModeToView();
1449
1450 emit modeChanged(m_mode, previousMode);
1451
1452 if (m_view->zoomLevel() != oldZoomLevel) {
1453 emit zoomLevelChanged(m_view->zoomLevel(), oldZoomLevel);
1454 }
1455 }
1456
1457 const bool hiddenFilesShown = props.hiddenFilesShown();
1458 if (hiddenFilesShown != m_model->showHiddenFiles()) {
1459 m_model->setShowHiddenFiles(hiddenFilesShown);
1460 emit hiddenFilesShownChanged(hiddenFilesShown);
1461 }
1462
1463 const bool groupedSorting = props.groupedSorting();
1464 if (groupedSorting != m_model->groupedSorting()) {
1465 m_model->setGroupedSorting(groupedSorting);
1466 emit groupedSortingChanged(groupedSorting);
1467 }
1468
1469 const QByteArray sortRole = props.sortRole();
1470 if (sortRole != m_model->sortRole()) {
1471 m_model->setSortRole(sortRole);
1472 emit sortRoleChanged(sortRole);
1473 }
1474
1475 const Qt::SortOrder sortOrder = props.sortOrder();
1476 if (sortOrder != m_model->sortOrder()) {
1477 m_model->setSortOrder(sortOrder);
1478 emit sortOrderChanged(sortOrder);
1479 }
1480
1481 const bool sortFoldersFirst = props.sortFoldersFirst();
1482 if (sortFoldersFirst != m_model->sortDirectoriesFirst()) {
1483 m_model->setSortDirectoriesFirst(sortFoldersFirst);
1484 emit sortFoldersFirstChanged(sortFoldersFirst);
1485 }
1486
1487 const QList<QByteArray> visibleRoles = props.visibleRoles();
1488 if (visibleRoles != m_visibleRoles) {
1489 const QList<QByteArray> previousVisibleRoles = m_visibleRoles;
1490 m_visibleRoles = visibleRoles;
1491 m_view->setVisibleRoles(visibleRoles);
1492 emit visibleRolesChanged(m_visibleRoles, previousVisibleRoles);
1493 }
1494
1495 const bool previewsShown = props.previewsShown();
1496 if (previewsShown != m_view->previewsShown()) {
1497 const int oldZoomLevel = zoomLevel();
1498
1499 m_view->setPreviewsShown(previewsShown);
1500 emit previewsShownChanged(previewsShown);
1501
1502 // Changing the preview-state might result in a changed zoom-level
1503 if (oldZoomLevel != zoomLevel()) {
1504 emit zoomLevelChanged(zoomLevel(), oldZoomLevel);
1505 }
1506 }
1507
1508 KItemListView* itemListView = m_container->controller()->view();
1509 if (itemListView->isHeaderVisible()) {
1510 KItemListHeader* header = itemListView->header();
1511 const QList<int> headerColumnWidths = props.headerColumnWidths();
1512 const int rolesCount = m_visibleRoles.count();
1513 if (headerColumnWidths.count() == rolesCount) {
1514 header->setAutomaticColumnResizing(false);
1515
1516 QHash<QByteArray, qreal> columnWidths;
1517 for (int i = 0; i < rolesCount; ++i) {
1518 columnWidths.insert(m_visibleRoles[i], headerColumnWidths[i]);
1519 }
1520 header->setColumnWidths(columnWidths);
1521 } else {
1522 header->setAutomaticColumnResizing(true);
1523 }
1524 }
1525
1526 m_view->endTransaction();
1527 }
1528
1529 void DolphinView::applyModeToView()
1530 {
1531 switch (m_mode) {
1532 case IconsView: m_view->setItemLayout(KFileItemListView::IconsLayout); break;
1533 case CompactView: m_view->setItemLayout(KFileItemListView::CompactLayout); break;
1534 case DetailsView: m_view->setItemLayout(KFileItemListView::DetailsLayout); break;
1535 default: Q_ASSERT(false); break;
1536 }
1537 }
1538
1539 void DolphinView::pasteToUrl(const KUrl& url)
1540 {
1541 KonqOperations* op = KonqOperations::doPasteV2(this, url);
1542 if (op) {
1543 m_clearSelectionBeforeSelectingNewItems = true;
1544 m_markFirstNewlySelectedItemAsCurrent = true;
1545 connect(op, SIGNAL(aboutToCreate(KUrl::List)), this, SLOT(slotAboutToCreate(KUrl::List)));
1546 }
1547 }
1548
1549 KUrl::List DolphinView::simplifiedSelectedUrls() const
1550 {
1551 KUrl::List urls;
1552
1553 const KFileItemList items = selectedItems();
1554 foreach (const KFileItem& item, items) {
1555 urls.append(item.url());
1556 }
1557
1558 if (itemsExpandable()) {
1559 // TODO: Check if we still need KDirModel for this in KDE 5.0
1560 urls = KDirModel::simplifiedUrlList(urls);
1561 }
1562
1563 return urls;
1564 }
1565
1566 QMimeData* DolphinView::selectionMimeData() const
1567 {
1568 const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
1569 const QSet<int> selectedIndexes = selectionManager->selectedItems();
1570
1571 return m_model->createMimeData(selectedIndexes);
1572 }
1573
1574 void DolphinView::updateWritableState()
1575 {
1576 const bool wasFolderWritable = m_isFolderWritable;
1577 m_isFolderWritable = true;
1578
1579 const KFileItem item = m_model->rootItem();
1580 if (!item.isNull()) {
1581 KFileItemListProperties capabilities(KFileItemList() << item);
1582 m_isFolderWritable = capabilities.supportsWriting();
1583 }
1584 if (m_isFolderWritable != wasFolderWritable) {
1585 emit writeStateChanged(m_isFolderWritable);
1586 }
1587 }
1588
1589 KUrl DolphinView::viewPropertiesUrl() const
1590 {
1591 if (m_viewPropertiesContext.isEmpty()) {
1592 return m_url;
1593 }
1594
1595 KUrl url;
1596 url.setProtocol(m_url.protocol());
1597 url.setPath(m_viewPropertiesContext);
1598 return url;
1599 }
1600
1601 #include "dolphinview.moc"