]> cloud.milkyroute.net Git - dolphin.git/blob - src/views/dolphindetailsview.cpp
64f964aa862e1df2a3ca6fa367b6a415c566e4e6
[dolphin.git] / src / views / dolphindetailsview.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) *
3 * Copyright (C) 2008 by Simon St. James (kdedevel@etotheipiplusone.com) *
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 "dolphindetailsview.h"
22
23 #include "additionalinfoaccessor.h"
24 #include "dolphinmodel.h"
25 #include "dolphinviewcontroller.h"
26 #include "dolphinfileitemdelegate.h"
27 #include "settings/dolphinsettings.h"
28 #include "dolphinsortfilterproxymodel.h"
29 #include "dolphinviewautoscroller.h"
30 #include "draganddrophelper.h"
31 #include "viewextensionsfactory.h"
32 #include "viewmodecontroller.h"
33 #include "viewproperties.h"
34 #include "zoomlevelinfo.h"
35
36 #include "dolphin_detailsmodesettings.h"
37 #include "dolphin_generalsettings.h"
38
39 #include <kdirmodel.h>
40 #include <kdirlister.h>
41 #include <klocale.h>
42 #include <kmenu.h>
43
44 #include <QApplication>
45 #include <QHeaderView>
46 #include <QScrollBar>
47
48 DolphinDetailsView::DolphinDetailsView(QWidget* parent,
49 DolphinViewController* dolphinViewController,
50 const ViewModeController* viewModeController,
51 DolphinSortFilterProxyModel* proxyModel) :
52 DolphinTreeView(parent),
53 m_autoResize(true),
54 m_dolphinViewController(dolphinViewController),
55 m_viewModeController(viewModeController),
56 m_extensionsFactory(0),
57 m_expandableFoldersAction(0),
58 m_expandedUrls(),
59 m_font(),
60 m_decorationSize()
61 {
62 const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
63 Q_ASSERT(settings != 0);
64 Q_ASSERT(dolphinViewController != 0);
65 Q_ASSERT(viewModeController != 0);
66
67 setLayoutDirection(Qt::LeftToRight);
68 setAcceptDrops(true);
69 setSortingEnabled(true);
70 setUniformRowHeights(true);
71 setSelectionBehavior(SelectItems);
72 setDragDropMode(QAbstractItemView::DragDrop);
73 setDropIndicatorShown(false);
74 setAlternatingRowColors(true);
75 setRootIsDecorated(settings->expandableFolders());
76 setItemsExpandable(settings->expandableFolders());
77 setEditTriggers(QAbstractItemView::NoEditTriggers);
78 setModel(proxyModel);
79
80 setMouseTracking(true);
81
82 const ViewProperties props(viewModeController->url());
83 setSortIndicatorSection(props.sorting());
84 setSortIndicatorOrder(props.sortOrder());
85
86 QHeaderView* headerView = header();
87 connect(headerView, SIGNAL(sectionClicked(int)),
88 this, SLOT(synchronizeSortingState(int)));
89 headerView->setContextMenuPolicy(Qt::CustomContextMenu);
90 connect(headerView, SIGNAL(customContextMenuRequested(const QPoint&)),
91 this, SLOT(configureSettings(const QPoint&)));
92 connect(headerView, SIGNAL(sectionResized(int, int, int)),
93 this, SLOT(slotHeaderSectionResized(int, int, int)));
94 connect(headerView, SIGNAL(sectionHandleDoubleClicked(int)),
95 this, SLOT(disableAutoResizing()));
96
97 connect(parent, SIGNAL(sortingChanged(DolphinView::Sorting)),
98 this, SLOT(setSortIndicatorSection(DolphinView::Sorting)));
99 connect(parent, SIGNAL(sortOrderChanged(Qt::SortOrder)),
100 this, SLOT(setSortIndicatorOrder(Qt::SortOrder)));
101
102 connect(this, SIGNAL(clicked(const QModelIndex&)),
103 dolphinViewController, SLOT(requestTab(const QModelIndex&)));
104 if (KGlobalSettings::singleClick()) {
105 connect(this, SIGNAL(clicked(const QModelIndex&)),
106 dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
107 } else {
108 connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
109 dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
110 }
111
112 connect(this, SIGNAL(entered(const QModelIndex&)),
113 this, SLOT(slotEntered(const QModelIndex&)));
114 connect(this, SIGNAL(viewportEntered()),
115 dolphinViewController, SLOT(emitViewportEntered()));
116 connect(viewModeController, SIGNAL(zoomLevelChanged(int)),
117 this, SLOT(setZoomLevel(int)));
118 connect(dolphinViewController->view(), SIGNAL(additionalInfoChanged()),
119 this, SLOT(updateColumnVisibility()));
120 connect(viewModeController, SIGNAL(activationChanged(bool)),
121 this, SLOT(slotActivationChanged(bool)));
122
123 if (settings->useSystemFont()) {
124 m_font = KGlobalSettings::generalFont();
125 } else {
126 m_font = QFont(settings->fontFamily(),
127 qRound(settings->fontSize()),
128 settings->fontWeight(),
129 settings->italicFont());
130 m_font.setPointSizeF(settings->fontSize());
131 }
132
133 setVerticalScrollMode(QTreeView::ScrollPerPixel);
134 setHorizontalScrollMode(QTreeView::ScrollPerPixel);
135
136 const DolphinView* view = dolphinViewController->view();
137 connect(view, SIGNAL(showPreviewChanged()),
138 this, SLOT(slotShowPreviewChanged()));
139
140
141 viewport()->installEventFilter(this);
142
143 connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
144 this, SLOT(slotGlobalSettingsChanged(int)));
145
146 m_expandableFoldersAction = new QAction(i18nc("@option:check", "Expandable Folders"), this);
147 m_expandableFoldersAction->setCheckable(true);
148 connect(m_expandableFoldersAction, SIGNAL(toggled(bool)),
149 this, SLOT(setFoldersExpandable(bool)));
150
151 connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(slotExpanded(const QModelIndex&)));
152 connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(slotCollapsed(const QModelIndex&)));
153
154 updateDecorationSize(view->showPreview());
155
156 m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController);
157 m_extensionsFactory->fileItemDelegate()->setMinimizedNameColumn(true);
158
159 KDirLister *dirLister = qobject_cast<KDirModel*>(proxyModel->sourceModel())->dirLister();
160 connect(dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(resizeColumns()));
161
162 // setFocus() must be called after m_extensionsFactory is initialised (see bug 240374).
163 setFocus();
164 }
165
166 DolphinDetailsView::~DolphinDetailsView()
167 {
168 }
169
170 QSet<KUrl> DolphinDetailsView::expandedUrls() const
171 {
172 return m_expandedUrls;
173 }
174
175 bool DolphinDetailsView::event(QEvent* event)
176 {
177 if (event->type() == QEvent::Polish) {
178 header()->setResizeMode(QHeaderView::Interactive);
179 updateColumnVisibility();
180 }
181
182 return DolphinTreeView::event(event);
183 }
184
185 QStyleOptionViewItem DolphinDetailsView::viewOptions() const
186 {
187 QStyleOptionViewItem viewOptions = DolphinTreeView::viewOptions();
188 viewOptions.font = m_font;
189 viewOptions.fontMetrics = QFontMetrics(m_font);
190 viewOptions.showDecorationSelected = true;
191 viewOptions.decorationSize = m_decorationSize;
192 return viewOptions;
193 }
194
195 void DolphinDetailsView::contextMenuEvent(QContextMenuEvent* event)
196 {
197 DolphinTreeView::contextMenuEvent(event);
198
199 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
200 m_expandableFoldersAction->setChecked(settings->expandableFolders());
201 m_dolphinViewController->triggerContextMenuRequest(event->pos(),
202 QList<QAction*>() << m_expandableFoldersAction);
203 }
204
205 void DolphinDetailsView::mousePressEvent(QMouseEvent* event)
206 {
207 m_dolphinViewController->requestActivation();
208
209 DolphinTreeView::mousePressEvent(event);
210
211 const QModelIndex index = indexAt(event->pos());
212 if (!index.isValid() || (index.column() != DolphinModel::Name)) {
213 // The mouse press is done somewhere outside the filename column
214 if (QApplication::mouseButtons() & Qt::MidButton) {
215 m_dolphinViewController->replaceUrlByClipboard();
216 }
217 }
218 }
219
220 void DolphinDetailsView::startDrag(Qt::DropActions supportedActions)
221 {
222 DragAndDropHelper::instance().startDrag(this, supportedActions, m_dolphinViewController);
223 DolphinTreeView::startDrag(supportedActions);
224 }
225
226 void DolphinDetailsView::dragEnterEvent(QDragEnterEvent* event)
227 {
228 if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) {
229 event->acceptProposedAction();
230 }
231 DolphinTreeView::dragEnterEvent(event);
232 }
233
234 void DolphinDetailsView::dragMoveEvent(QDragMoveEvent* event)
235 {
236 DolphinTreeView::dragMoveEvent(event);
237
238 if (DragAndDropHelper::instance().isMimeDataSupported(event->mimeData())) {
239 // Accept URL drops, independently from the destination item
240 event->acceptProposedAction();
241 }
242 }
243
244 void DolphinDetailsView::dropEvent(QDropEvent* event)
245 {
246 const QModelIndex index = indexAt(event->pos());
247 KFileItem item;
248 if (index.isValid() && (index.column() == DolphinModel::Name)) {
249 item = m_dolphinViewController->itemForIndex(index);
250 }
251 m_dolphinViewController->indicateDroppedUrls(item, m_viewModeController->url(), event);
252 DolphinTreeView::dropEvent(event);
253 }
254
255 void DolphinDetailsView::keyPressEvent(QKeyEvent* event)
256 {
257 DolphinTreeView::keyPressEvent(event);
258 m_dolphinViewController->handleKeyPressEvent(event);
259 }
260
261 void DolphinDetailsView::resizeEvent(QResizeEvent* event)
262 {
263 DolphinTreeView::resizeEvent(event);
264 if (m_autoResize) {
265 resizeColumns();
266 }
267 }
268
269 void DolphinDetailsView::wheelEvent(QWheelEvent* event)
270 {
271 const int step = m_decorationSize.height();
272 verticalScrollBar()->setSingleStep(step);
273 DolphinTreeView::wheelEvent(event);
274 }
275
276 void DolphinDetailsView::currentChanged(const QModelIndex& current, const QModelIndex& previous)
277 {
278 m_extensionsFactory->handleCurrentIndexChange(current, previous);
279 DolphinTreeView::currentChanged(current, previous);
280
281 // If folders are expanded, the width which is available for editing may have changed
282 // because it depends on the level of the current item in the folder hierarchy.
283 adjustMaximumSizeForEditing(current);
284 }
285
286 bool DolphinDetailsView::eventFilter(QObject* watched, QEvent* event)
287 {
288 if ((watched == viewport()) && (event->type() == QEvent::Leave)) {
289 // If the mouse is above an item and moved very fast outside the widget,
290 // no viewportEntered() signal might be emitted although the mouse has been moved
291 // above the viewport.
292 m_dolphinViewController->emitViewportEntered();
293 }
294
295 return DolphinTreeView::eventFilter(watched, event);
296 }
297
298 QRect DolphinDetailsView::visualRect(const QModelIndex& index) const
299 {
300 QRect rect = DolphinTreeView::visualRect(index);
301 const KFileItem item = m_dolphinViewController->itemForIndex(index);
302 if (!item.isNull()) {
303 const int width = DolphinFileItemDelegate::nameColumnWidth(item.text(), viewOptions());
304
305 if (width < rect.width()) {
306 rect.setWidth(width);
307 }
308 }
309
310 return rect;
311 }
312
313 bool DolphinDetailsView::acceptsDrop(const QModelIndex& index) const
314 {
315 if (index.isValid() && (index.column() == DolphinModel::Name)) {
316 // Accept drops above directories
317 const KFileItem item = m_dolphinViewController->itemForIndex(index);
318 return !item.isNull() && item.isDir();
319 }
320
321 return false;
322 }
323
324 void DolphinDetailsView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
325 {
326 removeExpandedIndexes(parent, start, end);
327 DolphinTreeView::rowsAboutToBeRemoved(parent, start, end);
328 }
329
330 void DolphinDetailsView::setSortIndicatorSection(DolphinView::Sorting sorting)
331 {
332 header()->setSortIndicator(sorting, header()->sortIndicatorOrder());
333 }
334
335 void DolphinDetailsView::setSortIndicatorOrder(Qt::SortOrder sortOrder)
336 {
337 header()->setSortIndicator(header()->sortIndicatorSection(), sortOrder);
338 }
339
340 void DolphinDetailsView::synchronizeSortingState(int column)
341 {
342 // The sorting has already been changed in QTreeView if this slot is
343 // invoked, but Dolphin is not informed about this.
344 DolphinView::Sorting sorting = DolphinSortFilterProxyModel::sortingForColumn(column);
345 const Qt::SortOrder sortOrder = header()->sortIndicatorOrder();
346 m_dolphinViewController->indicateSortingChange(sorting);
347 m_dolphinViewController->indicateSortOrderChange(sortOrder);
348 }
349
350 void DolphinDetailsView::slotEntered(const QModelIndex& index)
351 {
352 if (index.column() == DolphinModel::Name) {
353 m_dolphinViewController->emitItemEntered(index);
354 } else {
355 m_dolphinViewController->emitViewportEntered();
356 }
357 }
358
359 void DolphinDetailsView::setZoomLevel(int level)
360 {
361 const int size = ZoomLevelInfo::iconSizeForZoomLevel(level);
362 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
363
364 const bool showPreview = m_dolphinViewController->view()->showPreview();
365 if (showPreview) {
366 settings->setPreviewSize(size);
367 } else {
368 settings->setIconSize(size);
369 }
370
371 updateDecorationSize(showPreview);
372 }
373
374 void DolphinDetailsView::slotShowPreviewChanged()
375 {
376 const DolphinView* view = m_dolphinViewController->view();
377 updateDecorationSize(view->showPreview());
378 }
379
380 void DolphinDetailsView::configureSettings(const QPoint& pos)
381 {
382 KMenu popup(this);
383 popup.addTitle(i18nc("@title:menu", "Columns"));
384
385 // Add checkbox items for each column
386 QHeaderView* headerView = header();
387 const int columns = model()->columnCount();
388 for (int i = 0; i < columns; ++i) {
389 const int logicalIndex = headerView->logicalIndex(i);
390 const QString text = model()->headerData(logicalIndex, Qt::Horizontal).toString();
391 if (!text.isEmpty()) {
392 QAction* action = popup.addAction(text);
393 action->setCheckable(true);
394 action->setChecked(!headerView->isSectionHidden(logicalIndex));
395 action->setData(logicalIndex);
396 action->setEnabled(logicalIndex != DolphinModel::Name);
397 }
398 }
399 popup.addSeparator();
400
401 QAction* activatedAction = popup.exec(header()->mapToGlobal(pos));
402 if (activatedAction != 0) {
403 const bool show = activatedAction->isChecked();
404 const int columnIndex = activatedAction->data().toInt();
405
406 KFileItemDelegate::InformationList list = m_dolphinViewController->view()->additionalInfo();
407 const KFileItemDelegate::Information info = infoForColumn(columnIndex);
408 if (show) {
409 Q_ASSERT(!list.contains(info));
410 list.append(info);
411 } else {
412 Q_ASSERT(list.contains(info));
413 const int index = list.indexOf(info);
414 list.removeAt(index);
415 }
416
417 m_dolphinViewController->indicateAdditionalInfoChange(list);
418 setColumnHidden(columnIndex, !show);
419 resizeColumns();
420 }
421 }
422
423 void DolphinDetailsView::updateColumnVisibility()
424 {
425 QHeaderView* headerView = header();
426 disconnect(headerView, SIGNAL(sectionMoved(int, int, int)),
427 this, SLOT(saveColumnPositions()));
428
429 const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
430 const QList<int> columnPositions = settings->columnPositions();
431
432 const KFileItemDelegate::InformationList list = m_dolphinViewController->view()->additionalInfo();
433 for (int i = DolphinModel::Name; i < DolphinModel::ExtraColumnCount; ++i) {
434 const KFileItemDelegate::Information info = infoForColumn(i);
435 const bool hide = !list.contains(info) && (i != DolphinModel::Name);
436 if (isColumnHidden(i) != hide) {
437 setColumnHidden(i, hide);
438 }
439
440 // If the list columnPositions has been written by an older Dolphin version,
441 // its length might be smaller than DolphinModel::ExtraColumnCount. Therefore,
442 // we have to check if item number i exists before accessing it.
443 if (i < columnPositions.length()) {
444 const int position = columnPositions[i];
445
446 // The position might be outside the correct range if the list columnPositions
447 // has been written by a newer Dolphin version with more columns.
448 if (position < DolphinModel::ExtraColumnCount) {
449 const int from = headerView->visualIndex(i);
450 headerView->moveSection(from, position);
451 }
452 }
453 }
454
455 resizeColumns();
456
457 connect(headerView, SIGNAL(sectionMoved(int, int, int)),
458 this, SLOT(saveColumnPositions()));
459 }
460
461 void DolphinDetailsView::resizeColumns()
462 {
463 // Using the resize mode QHeaderView::ResizeToContents is too slow (it takes
464 // around 3 seconds for each (!) resize operation when having > 10000 items).
465 // This gets a problem especially when opening large directories, where several
466 // resize operations are received for showing the currently available items during
467 // loading (the application hangs around 20 seconds when loading > 10000 items).
468
469 QHeaderView* headerView = header();
470 const int rowCount = model()->rowCount();
471 QFontMetrics fontMetrics(viewport()->font());
472
473 // Define the maximum number of rows, where an exact (but expensive) calculation
474 // of the widths is done.
475 const int maxRowCount = 200;
476
477 // Calculate the required with for each column and store it in columnWidth[]
478 int columnWidth[DolphinModel::ExtraColumnCount];
479
480 for (int column = 0; column < DolphinModel::ExtraColumnCount; ++column) {
481 columnWidth[column] = 0;
482 if (!isColumnHidden(column)) {
483 // Calculate the required width for the current column and consider only
484 // up to maxRowCount columns for performance reasons
485 if (rowCount > 0) {
486 const QAbstractProxyModel* proxyModel = qobject_cast<const QAbstractProxyModel*>(model());
487 const KDirModel* dirModel = qobject_cast<const KDirModel*>(proxyModel->sourceModel());
488
489 const int count = qMin(rowCount, maxRowCount);
490 const QStyleOptionViewItem option = viewOptions();
491 for (int row = 0; row < count; ++row) {
492 const QModelIndex index = dirModel->index(row, column);
493 const int width = itemDelegate()->sizeHint(option, index).width();
494 if (width > columnWidth[column]) {
495 columnWidth[column] = width;
496 }
497 }
498 }
499
500 // Assure that the required width is sufficient for the header too
501 const int logicalIndex = headerView->logicalIndex(column);
502 const QString headline = model()->headerData(logicalIndex, Qt::Horizontal).toString();
503 // TODO: check Qt-sources which left/right-gap is used for the headlines
504 const int headlineWidth = fontMetrics.width(headline) + 20;
505
506 columnWidth[column] = qMax(columnWidth[column], headlineWidth);
507 }
508 }
509
510 // Resize all columns except of the name column
511 int requiredWidth = 0;
512 for (int column = KDirModel::Size; column < DolphinModel::ExtraColumnCount; ++column) {
513 if (!isColumnHidden(column)) {
514 requiredWidth += columnWidth[column];
515 headerView->resizeSection(column, columnWidth[column]);
516 }
517 }
518
519 // Resize the name column in a way that the whole available width is used
520 columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth;
521
522 const int minNameWidth = 300;
523 if (columnWidth[KDirModel::Name] < minNameWidth) {
524 columnWidth[KDirModel::Name] = minNameWidth;
525
526 if ((rowCount > 0) && (rowCount < maxRowCount)) {
527 // Try to decrease the name column width without clipping any text
528 const int nameWidth = sizeHintForColumn(DolphinModel::Name);
529 if (nameWidth + requiredWidth <= viewport()->width()) {
530 columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth;
531 } else if (nameWidth < minNameWidth) {
532 columnWidth[KDirModel::Name] = nameWidth;
533 }
534 }
535 }
536
537 headerView->resizeSection(KDirModel::Name, columnWidth[KDirModel::Name]);
538 }
539
540 void DolphinDetailsView::saveColumnPositions()
541 {
542 QList<int> columnPositions;
543 for (int i = DolphinModel::Name; i < DolphinModel::ExtraColumnCount; ++i) {
544 columnPositions.append(header()->visualIndex(i));
545 }
546
547 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
548 settings->setColumnPositions(columnPositions);
549 }
550
551 void DolphinDetailsView::slotHeaderSectionResized(int logicalIndex, int oldSize, int newSize)
552 {
553 Q_UNUSED(logicalIndex);
554 Q_UNUSED(oldSize);
555 Q_UNUSED(newSize);
556 // If the user changes the size of the headers, the autoresize feature should be
557 // turned off. As there is no dedicated interface to find out whether the header
558 // section has been resized by the user or by a resize event, another approach is used.
559 // Attention: Take care when changing the if-condition to verify that there is no
560 // regression in combination with bug 178630 (see fix in comment #8).
561 if ((QApplication::mouseButtons() & Qt::LeftButton) && header()->underMouse()) {
562 disableAutoResizing();
563 }
564
565 adjustMaximumSizeForEditing(currentIndex());
566 }
567
568 void DolphinDetailsView::slotActivationChanged(bool active)
569 {
570 setAlternatingRowColors(active);
571 }
572
573 void DolphinDetailsView::disableAutoResizing()
574 {
575 m_autoResize = false;
576 }
577
578 void DolphinDetailsView::requestActivation()
579 {
580 m_dolphinViewController->requestActivation();
581 }
582
583 void DolphinDetailsView::slotGlobalSettingsChanged(int category)
584 {
585 Q_UNUSED(category);
586
587 const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
588 Q_ASSERT(settings != 0);
589 if (settings->useSystemFont()) {
590 m_font = KGlobalSettings::generalFont();
591 }
592 // Disconnect then reconnect, since the settings have been changed, the connection requirements may have also.
593 disconnect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
594 disconnect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
595 if (KGlobalSettings::singleClick()) {
596 connect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
597 } else {
598 connect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
599 }
600 }
601
602
603 void DolphinDetailsView::setFoldersExpandable(bool expandable)
604 {
605 if (!expandable) {
606 // Collapse all expanded folders, as QTreeView::setItemsExpandable(false)
607 // does not do this task
608 const int rowCount = model()->rowCount();
609 for (int row = 0; row < rowCount; ++row) {
610 setExpanded(model()->index(row, 0), false);
611 }
612 }
613 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
614 settings->setExpandableFolders(expandable);
615 setRootIsDecorated(expandable);
616 setItemsExpandable(expandable);
617
618 // The width of the space which is available for editing has changed
619 // because of the (dis)appearance of the expanding toggles
620 adjustMaximumSizeForEditing(currentIndex());
621 }
622
623 void DolphinDetailsView::slotExpanded(const QModelIndex& index)
624 {
625 KFileItem item = m_dolphinViewController->itemForIndex(index);
626 if (!item.isNull()) {
627 m_expandedUrls.insert(item.url());
628 }
629 }
630
631 void DolphinDetailsView::slotCollapsed(const QModelIndex& index)
632 {
633 KFileItem item = m_dolphinViewController->itemForIndex(index);
634 if (!item.isNull()) {
635 m_expandedUrls.remove(item.url());
636 }
637 }
638
639 void DolphinDetailsView::removeExpandedIndexes(const QModelIndex& parent, int start, int end)
640 {
641 if (m_expandedUrls.isEmpty()) {
642 return;
643 }
644
645 for (int row = start; row <= end; row++) {
646 const QModelIndex index = model()->index(row, 0, parent);
647 if (isExpanded(index)) {
648 slotCollapsed(index);
649 removeExpandedIndexes(index, 0, model()->rowCount(index) - 1);
650 }
651 }
652 }
653
654 void DolphinDetailsView::updateDecorationSize(bool showPreview)
655 {
656 DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
657 const int iconSize = showPreview ? settings->previewSize() : settings->iconSize();
658 setIconSize(QSize(iconSize, iconSize));
659 m_decorationSize = QSize(iconSize, iconSize);
660
661 if (m_extensionsFactory) {
662 // The old maximumSize used by KFileItemDelegate is not valid any more after the icon size change.
663 // It must be discarded before doItemsLayout() is called (see bug 234600).
664 m_extensionsFactory->fileItemDelegate()->setMaximumSize(QSize());
665 }
666
667 doItemsLayout();
668
669 // Calculate the new maximumSize for KFileItemDelegate after the icon size change.
670 QModelIndex current = currentIndex();
671 if (current.isValid()) {
672 adjustMaximumSizeForEditing(current);
673 }
674 }
675
676 KFileItemDelegate::Information DolphinDetailsView::infoForColumn(int columnIndex) const
677 {
678 return AdditionalInfoAccessor::instance().keyForColumn(columnIndex);
679 }
680
681 void DolphinDetailsView::adjustMaximumSizeForEditing(const QModelIndex& index)
682 {
683 // Make sure that the full width of the "Name" column is available for "Rename Inline".
684 // Before we do that, we have to check if m_extensionsFactory has been initialised because
685 // it is possible that we end up here before the constructor is finished (see bug 257035)
686 if (m_extensionsFactory) {
687 m_extensionsFactory->fileItemDelegate()->setMaximumSize(QTreeView::visualRect(index).size());
688 }
689 }
690
691 #include "dolphindetailsview.moc"