X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/85aec92f819eae5a6189bd3ec25cff44dce3ae19..7a0cbf257323176be420ea5d29f0d466cd682193:/src/dolphindetailsview.cpp diff --git a/src/dolphindetailsview.cpp b/src/dolphindetailsview.cpp index f4b8cd162..8292db8aa 100644 --- a/src/dolphindetailsview.cpp +++ b/src/dolphindetailsview.cpp @@ -23,11 +23,11 @@ #include "dolphinmodel.h" #include "dolphincontroller.h" #include "dolphinfileitemdelegate.h" -#include "dolphinsettings.h" +#include "settings/dolphinsettings.h" #include "dolphinsortfilterproxymodel.h" #include "dolphinviewautoscroller.h" #include "draganddrophelper.h" -#include "selectionmanager.h" +#include "viewextensionsfactory.h" #include "viewproperties.h" #include "zoomlevelinfo.h" @@ -38,7 +38,6 @@ #include #include -#include #include #include #include @@ -46,7 +45,9 @@ #include #include -DolphinDetailsView::DolphinDetailsView(QWidget* parent, DolphinController* controller) : +DolphinDetailsView::DolphinDetailsView(QWidget* parent, + DolphinController* controller, + DolphinSortFilterProxyModel* proxyModel) : QTreeView(parent), m_autoResize(true), m_expandingTogglePressed(false), @@ -54,7 +55,9 @@ DolphinDetailsView::DolphinDetailsView(QWidget* parent, DolphinController* contr m_useDefaultIndexAt(true), m_ignoreScrollTo(false), m_controller(controller), - m_selectionManager(0), + m_extensionsFactory(0), + m_expandableFoldersAction(0), + m_expandedUrls(), m_font(), m_decorationSize(), m_band() @@ -74,9 +77,9 @@ DolphinDetailsView::DolphinDetailsView(QWidget* parent, DolphinController* contr setRootIsDecorated(settings->expandableFolders()); setItemsExpandable(settings->expandableFolders()); setEditTriggers(QAbstractItemView::NoEditTriggers); + setModel(proxyModel); setMouseTracking(true); - new DolphinViewAutoScroller(this); const ViewProperties props(controller->url()); setSortIndicatorSection(props.sorting()); @@ -87,7 +90,7 @@ DolphinDetailsView::DolphinDetailsView(QWidget* parent, DolphinController* contr this, SLOT(synchronizeSortingState(int))); headerView->setContextMenuPolicy(Qt::CustomContextMenu); connect(headerView, SIGNAL(customContextMenuRequested(const QPoint&)), - this, SLOT(configureColumns(const QPoint&))); + this, SLOT(configureSettings(const QPoint&))); connect(headerView, SIGNAL(sectionResized(int, int, int)), this, SLOT(slotHeaderSectionResized(int, int, int))); connect(headerView, SIGNAL(sectionHandleDoubleClicked(int)), @@ -108,14 +111,6 @@ DolphinDetailsView::DolphinDetailsView(QWidget* parent, DolphinController* contr controller, SLOT(triggerItem(const QModelIndex&))); } - if (DolphinSettings::instance().generalSettings()->showSelectionToggle()) { - m_selectionManager = new SelectionManager(this); - connect(m_selectionManager, SIGNAL(selectionChanged()), - this, SLOT(requestActivation())); - connect(m_controller, SIGNAL(urlChanged(const KUrl&)), - m_selectionManager, SLOT(reset())); - } - connect(this, SIGNAL(entered(const QModelIndex&)), this, SLOT(slotEntered(const QModelIndex&))); connect(this, SIGNAL(viewportEntered()), @@ -131,9 +126,10 @@ DolphinDetailsView::DolphinDetailsView(QWidget* parent, DolphinController* contr m_font = KGlobalSettings::generalFont(); } else { m_font = QFont(settings->fontFamily(), - settings->fontSize(), + qRound(settings->fontSize()), settings->fontWeight(), settings->italicFont()); + m_font.setPointSizeF(settings->fontSize()); } setVerticalScrollMode(QTreeView::ScrollPerPixel); @@ -143,32 +139,71 @@ DolphinDetailsView::DolphinDetailsView(QWidget* parent, DolphinController* contr connect(view, SIGNAL(showPreviewChanged()), this, SLOT(slotShowPreviewChanged())); - updateDecorationSize(view->showPreview()); setFocus(); viewport()->installEventFilter(this); - connect(KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()), - this, SLOT(updateFont())); + connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), + this, SLOT(slotGlobalSettingsChanged(int))); m_useDefaultIndexAt = false; + + m_expandableFoldersAction = new QAction(i18nc("@option:check", "Expandable Folders"), this); + m_expandableFoldersAction->setCheckable(true); + connect(m_expandableFoldersAction, SIGNAL(toggled(bool)), + this, SLOT(setFoldersExpandable(bool))); + + connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(slotExpanded(const QModelIndex&))); + connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(slotCollapsed(const QModelIndex&))); + + updateDecorationSize(view->showPreview()); + + m_extensionsFactory = new ViewExtensionsFactory(this, controller); + m_extensionsFactory->fileItemDelegate()->setMinimizedNameColumn(true); + m_extensionsFactory->setAutoFolderExpandingEnabled(settings->expandableFolders()); } DolphinDetailsView::~DolphinDetailsView() { } -bool DolphinDetailsView::event(QEvent* event) +QSet DolphinDetailsView::expandedUrls() const { - if (event->type() == QEvent::Polish) { - QHeaderView* headerView = header(); - headerView->setResizeMode(QHeaderView::Interactive); - headerView->setMovable(false); + return m_expandedUrls; +} + +QRegion DolphinDetailsView::visualRegionForSelection(const QItemSelection& selection) const +{ + // We have to make sure that the visualRect of each model index is inside the region. + // QTreeView::visualRegionForSelection does not do it right because it assumes implicitly + // that all visualRects have the same width, which is in general not the case here. + QRegion selectionRegion; + const QModelIndexList indexes = selection.indexes(); + + foreach(const QModelIndex& index, indexes) { + selectionRegion += visualRect(index); + } + return selectionRegion; +} + +bool DolphinDetailsView::event(QEvent* event) +{ + switch (event->type()) { + case QEvent::Polish: + header()->setResizeMode(QHeaderView::Interactive); updateColumnVisibility(); + break; - hideColumn(DolphinModel::Rating); - hideColumn(DolphinModel::Tags); + case QEvent::FocusOut: + // If a key-press triggers an action that e. g. opens a dialog, the + // widget gets no key-release event. Assure that the pressed state + // is reset to prevent accidently setting the current index during a selection. + m_keyPressed = false; + break; + + default: + break; } return QTreeView::event(event); @@ -178,6 +213,7 @@ QStyleOptionViewItem DolphinDetailsView::viewOptions() const { QStyleOptionViewItem viewOptions = QTreeView::viewOptions(); viewOptions.font = m_font; + viewOptions.fontMetrics = QFontMetrics(m_font); viewOptions.showDecorationSelected = true; viewOptions.decorationSize = m_decorationSize; return viewOptions; @@ -186,7 +222,11 @@ QStyleOptionViewItem DolphinDetailsView::viewOptions() const void DolphinDetailsView::contextMenuEvent(QContextMenuEvent* event) { QTreeView::contextMenuEvent(event); - m_controller->triggerContextMenuRequest(event->pos()); + + DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + m_expandableFoldersAction->setChecked(settings->expandableFolders()); + m_controller->triggerContextMenuRequest(event->pos(), + QList() << m_expandableFoldersAction); } void DolphinDetailsView::mousePressEvent(QMouseEvent* event) @@ -196,21 +236,14 @@ void DolphinDetailsView::mousePressEvent(QMouseEvent* event) const QModelIndex current = currentIndex(); QTreeView::mousePressEvent(event); - m_expandingTogglePressed = false; + m_expandingTogglePressed = isAboveExpandingToggle(event->pos()); + const QModelIndex index = indexAt(event->pos()); const bool updateState = index.isValid() && (index.column() == DolphinModel::Name) && (event->button() == Qt::LeftButton); if (updateState) { - // TODO: See comment in DolphinIconsView::mousePressEvent(). Only update - // the state if no expanding/collapsing area has been hit: - const QRect rect = visualRect(index); - if (event->pos().x() >= rect.x() + indentation()) { - setState(QAbstractItemView::DraggingState); - } else { - m_expandingTogglePressed = true; - kDebug() << "m_expandingTogglePressed " << m_expandingTogglePressed; - } + setState(QAbstractItemView::DraggingState); } if (!index.isValid() || (index.column() != DolphinModel::Name)) { @@ -219,8 +252,8 @@ void DolphinDetailsView::mousePressEvent(QMouseEvent* event) m_controller->replaceUrlByClipboard(); } - const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers(); - if (!(modifier & Qt::ShiftModifier) && !(modifier & Qt::ControlModifier)) { + const Qt::KeyboardModifiers mod = QApplication::keyboardModifiers(); + if (!m_expandingTogglePressed && !(mod & Qt::ShiftModifier) && !(mod & Qt::ControlModifier)) { clearSelection(); } @@ -236,9 +269,8 @@ void DolphinDetailsView::mousePressEvent(QMouseEvent* event) m_band.show = true; // Incremental update data will not be useful - start from scratch. m_band.ignoreOldInfo = true; - const QPoint pos = contentsPos(); const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); - m_band.origin = event->pos() + pos + scrollPos; + m_band.origin = event->pos() + scrollPos; m_band.destination = m_band.origin; m_band.originalSelection = selectionModel()->selection(); } @@ -247,6 +279,14 @@ void DolphinDetailsView::mousePressEvent(QMouseEvent* event) void DolphinDetailsView::mouseMoveEvent(QMouseEvent* event) { + if (m_expandingTogglePressed) { + // Per default QTreeView starts either a selection or a drag operation when dragging + // the expanding toggle button (Qt-issue - see TODO comment in DolphinIconsView::mousePressEvent()). + // Turn off this behavior in Dolphin to stay predictable: + setState(QAbstractItemView::NoState); + return; + } + if (m_band.show) { const QPoint mousePos = event->pos(); const QModelIndex index = indexAt(mousePos); @@ -268,31 +308,25 @@ void DolphinDetailsView::mouseMoveEvent(QMouseEvent* event) // QTreeView::mouseMoveEvent(event); QAbstractItemView::mouseMoveEvent(event); } - - if (m_expandingTogglePressed) { - // Per default QTreeView starts either a selection or a drag operation when dragging - // the expanding toggle button (Qt-issue - see TODO comment in DolphinIconsView::mousePressEvent()). - // Turn off this behavior in Dolphin to stay predictable: - clearSelection(); - setState(QAbstractItemView::NoState); - } } void DolphinDetailsView::mouseReleaseEvent(QMouseEvent* event) { - const QModelIndex index = indexAt(event->pos()); - if (index.isValid() && (index.column() == DolphinModel::Name)) { - QTreeView::mouseReleaseEvent(event); - } else { - // don't change the current index if the cursor is released - // above any other column than the name column, as the other - // columns act as viewport - const QModelIndex current = currentIndex(); - QTreeView::mouseReleaseEvent(event); - selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current); + if (!m_expandingTogglePressed) { + const QModelIndex index = indexAt(event->pos()); + if (index.isValid() && (index.column() == DolphinModel::Name)) { + QTreeView::mouseReleaseEvent(event); + } else { + // don't change the current index if the cursor is released + // above any other column than the name column, as the other + // columns act as viewport + const QModelIndex current = currentIndex(); + QTreeView::mouseReleaseEvent(event); + selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current); + } } - m_expandingTogglePressed = false; + if (m_band.show) { setState(NoState); updateElasticBand(); @@ -405,18 +439,7 @@ void DolphinDetailsView::resizeEvent(QResizeEvent* event) void DolphinDetailsView::wheelEvent(QWheelEvent* event) { - if (m_selectionManager != 0) { - m_selectionManager->reset(); - } - - // let Ctrl+wheel events propagate to the DolphinView for icon zooming - if (event->modifiers() & Qt::ControlModifier) { - event->ignore(); - return; - } - - const int height = m_decorationSize.height(); - const int step = (height >= KIconLoader::SizeHuge) ? height / 10 : (KIconLoader::SizeHuge - height) / 2; + const int step = m_decorationSize.height(); verticalScrollBar()->setSingleStep(step); QTreeView::wheelEvent(event); } @@ -424,11 +447,12 @@ void DolphinDetailsView::wheelEvent(QWheelEvent* event) void DolphinDetailsView::currentChanged(const QModelIndex& current, const QModelIndex& previous) { QTreeView::currentChanged(current, previous); + m_extensionsFactory->handleCurrentIndexChange(current, previous); // Stay consistent with QListView: When changing the current index by key presses, // also change the selection. if (m_keyPressed) { - selectionModel()->select(current, QItemSelectionModel::ClearAndSelect); + setCurrentIndex(current); } } @@ -449,11 +473,23 @@ QModelIndex DolphinDetailsView::indexAt(const QPoint& point) const // the blank portion of the name column counts as empty space const QModelIndex index = QTreeView::indexAt(point); const bool isAboveEmptySpace = !m_useDefaultIndexAt && - (index.column() == KDirModel::Name) && !nameColumnRect(index).contains(point); + (index.column() == KDirModel::Name) && !visualRect(index).contains(point); return isAboveEmptySpace ? QModelIndex() : index; } -void DolphinDetailsView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) +QRect DolphinDetailsView::visualRect(const QModelIndex& index) const +{ + QRect rect = QTreeView::visualRect(index); + const KFileItem item = m_controller->itemForIndex(index); + if (!item.isNull()) { + const int width = DolphinFileItemDelegate::nameColumnWidth(item.text(), viewOptions()); + rect.setWidth(width); + } + + return rect; +} + +void DolphinDetailsView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command) { // We must override setSelection() as Qt calls it internally and when this happens // we must ensure that the default indexAt() is used. @@ -462,7 +498,6 @@ void DolphinDetailsView::setSelection(const QRect &rect, QItemSelectionModel::Se QTreeView::setSelection(rect, command); m_useDefaultIndexAt = false; } else { - // Use our own elastic band selection algorithm updateElasticBandSelection(); } @@ -470,21 +505,19 @@ void DolphinDetailsView::setSelection(const QRect &rect, QItemSelectionModel::Se void DolphinDetailsView::scrollTo(const QModelIndex & index, ScrollHint hint) { - if (m_ignoreScrollTo) - return; - QTreeView::scrollTo(index, hint); + if (!m_ignoreScrollTo) { + QTreeView::scrollTo(index, hint); + } } void DolphinDetailsView::setSortIndicatorSection(DolphinView::Sorting sorting) { - QHeaderView* headerView = header(); - headerView->setSortIndicator(sorting, headerView->sortIndicatorOrder()); + header()->setSortIndicator(sorting, header()->sortIndicatorOrder()); } void DolphinDetailsView::setSortIndicatorOrder(Qt::SortOrder sortOrder) { - QHeaderView* headerView = header(); - headerView->setSortIndicator(headerView->sortIndicatorSection(), sortOrder); + header()->setSortIndicator(header()->sortIndicatorSection(), sortOrder); } void DolphinDetailsView::synchronizeSortingState(int column) @@ -514,11 +547,12 @@ void DolphinDetailsView::updateElasticBand() m_band.destination = viewport()->mapFromGlobal(QCursor::pos()) + scrollPos; // Going above the (logical) top-left of the view causes complications during selection; // we may as well prevent it. - if (m_band.destination.y() < 0) + if (m_band.destination.y() < 0) { m_band.destination.setY(0); - if (m_band.destination.x() < 0) + } + if (m_band.destination.x() < 0) { m_band.destination.setX(0); - + } dirtyRegion = dirtyRegion.united(elasticBandRect()); setDirtyRegion(dirtyRegion); } @@ -526,11 +560,10 @@ void DolphinDetailsView::updateElasticBand() QRect DolphinDetailsView::elasticBandRect() const { - const QPoint pos(contentsPos()); const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value()); - const QPoint topLeft = m_band.origin - pos - scrollPos; - const QPoint bottomRight = m_band.destination - pos - scrollPos; + const QPoint topLeft = m_band.origin - scrollPos; + const QPoint bottomRight = m_band.destination - scrollPos; return QRect(topLeft, bottomRight).normalized(); } @@ -549,27 +582,30 @@ void DolphinDetailsView::setZoomLevel(int level) updateDecorationSize(showPreview); } - void DolphinDetailsView::slotShowPreviewChanged() { const DolphinView* view = m_controller->dolphinView(); updateDecorationSize(view->showPreview()); } -void DolphinDetailsView::configureColumns(const QPoint& pos) +void DolphinDetailsView::configureSettings(const QPoint& pos) { KMenu popup(this); popup.addTitle(i18nc("@title:menu", "Columns")); + // add checkbox items for each column QHeaderView* headerView = header(); - for (int i = DolphinModel::Size; i <= DolphinModel::Type; ++i) { + const int columns = model()->columnCount(); + for (int i = 0; i < columns; ++i) { const int logicalIndex = headerView->logicalIndex(i); - const QString text = model()->headerData(i, Qt::Horizontal).toString(); + const QString text = model()->headerData(logicalIndex, Qt::Horizontal).toString(); QAction* action = popup.addAction(text); action->setCheckable(true); action->setChecked(!headerView->isSectionHidden(logicalIndex)); - action->setData(i); + action->setData(logicalIndex); + action->setEnabled(logicalIndex != DolphinModel::Name); } + popup.addSeparator(); QAction* activatedAction = popup.exec(header()->mapToGlobal(pos)); if (activatedAction != 0) { @@ -595,16 +631,41 @@ void DolphinDetailsView::configureColumns(const QPoint& pos) void DolphinDetailsView::updateColumnVisibility() { + QHeaderView* headerView = header(); + disconnect(headerView, SIGNAL(sectionMoved(int, int, int)), + this, SLOT(saveColumnPositions())); + + const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + const QList columnPositions = settings->columnPositions(); + const KFileItemDelegate::InformationList list = m_controller->dolphinView()->additionalInfo(); - for (int i = DolphinModel::Size; i <= DolphinModel::Type; ++i) { + for (int i = DolphinModel::Name; i <= DolphinModel::Version; ++i) { const KFileItemDelegate::Information info = infoForColumn(i); - const bool hide = !list.contains(info); + const bool hide = !list.contains(info) && (i != DolphinModel::Name); if (isColumnHidden(i) != hide) { setColumnHidden(i, hide); } + + const int from = headerView->visualIndex(i); + headerView->moveSection(from, columnPositions[i]); } - + resizeColumns(); + + connect(headerView, SIGNAL(sectionMoved(int, int, int)), + this, SLOT(saveColumnPositions())); + +} + +void DolphinDetailsView::saveColumnPositions() +{ + QList columnPositions; + for (int i = DolphinModel::Name; i <= DolphinModel::Version; ++i) { + columnPositions.append(header()->visualIndex(i)); + } + + DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + settings->setColumnPositions(columnPositions); } void DolphinDetailsView::slotHeaderSectionResized(int logicalIndex, int oldSize, int newSize) @@ -614,8 +675,10 @@ void DolphinDetailsView::slotHeaderSectionResized(int logicalIndex, int oldSize, Q_UNUSED(newSize); // If the user changes the size of the headers, the autoresize feature should be // turned off. As there is no dedicated interface to find out whether the header - // section has been resized by the user or by a resize event, the following approach is used: - if ((QApplication::mouseButtons() & Qt::LeftButton) && isVisible()) { + // section has been resized by the user or by a resize event, another approach is used. + // Attention: Take care when changing the if-condition to verify that there is no + // regression in combination with bug 178630 (see fix in comment #8). + if ((QApplication::mouseButtons() & Qt::LeftButton) && header()->underMouse()) { disableAutoResizing(); } } @@ -635,14 +698,23 @@ void DolphinDetailsView::requestActivation() m_controller->requestActivation(); } -void DolphinDetailsView::updateFont() +void DolphinDetailsView::slotGlobalSettingsChanged(int category) { + Q_UNUSED(category); + const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); Q_ASSERT(settings != 0); - if (settings->useSystemFont()) { m_font = KGlobalSettings::generalFont(); } + //Disconnect then reconnect, since the settings have been changed, the connection requirements may have also. + disconnect(this, SIGNAL(clicked(QModelIndex)), m_controller, SLOT(triggerItem(QModelIndex))); + disconnect(this, SIGNAL(doubleClicked(QModelIndex)), m_controller, SLOT(triggerItem(QModelIndex))); + if (KGlobalSettings::singleClick()) { + connect(this, SIGNAL(clicked(QModelIndex)), m_controller, SLOT(triggerItem(QModelIndex))); + } else { + connect(this, SIGNAL(doubleClicked(QModelIndex)), m_controller, SLOT(triggerItem(QModelIndex))); + } } void DolphinDetailsView::updateElasticBandSelection() @@ -706,8 +778,7 @@ void DolphinDetailsView::updateElasticBandSelection() return; } } - } - else { + } else { // This is the only piece of optimization data that needs to be explicitly // discarded. m_band.lastSelectionOrigin = QPoint(); @@ -759,7 +830,7 @@ void DolphinDetailsView::updateElasticBandSelection() QModelIndex toggleIndexRangeBegin = QModelIndex(); do { - QRect currIndexRect = nameColumnRect(currIndex); + QRect currIndexRect = visualRect(currIndex); // Update some optimization info as we go. const int cr = currIndexRect.right(); @@ -821,6 +892,7 @@ void DolphinDetailsView::updateElasticBandSelection() currIndex = nextIndex; } while (!allItemsInBoundDone); + selectionModel()->select(itemsToToggle, QItemSelectionModel::Toggle); m_band.lastSelectionOrigin = m_band.origin; @@ -828,36 +900,67 @@ void DolphinDetailsView::updateElasticBandSelection() m_band.ignoreOldInfo = false; } -void DolphinDetailsView::updateDecorationSize(bool showPreview) +void DolphinDetailsView::setFoldersExpandable(bool expandable) { + if (!expandable) { + // collapse all expanded folders, as QTreeView::setItemsExpandable(false) + // does not do this task + const int rowCount = model()->rowCount(); + for (int row = 0; row < rowCount; ++row) { + setExpanded(model()->index(row, 0), false); + } + } DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); - const int iconSize = showPreview ? settings->previewSize() : settings->iconSize(); - setIconSize(QSize(iconSize, iconSize)); - m_decorationSize = QSize(iconSize, iconSize); + settings->setExpandableFolders(expandable); + setRootIsDecorated(expandable); + setItemsExpandable(expandable); +} - if (m_selectionManager != 0) { - m_selectionManager->reset(); +void DolphinDetailsView::slotExpanded(const QModelIndex& index) +{ + KFileItem item = m_controller->itemForIndex(index); + if (!item.isNull()) { + m_expandedUrls.insert(item.url()); } +} - doItemsLayout(); +void DolphinDetailsView::slotCollapsed(const QModelIndex& index) +{ + KFileItem item = m_controller->itemForIndex(index); + if (!item.isNull()) { + m_expandedUrls.remove(item.url()); + } } -QPoint DolphinDetailsView::contentsPos() const +void DolphinDetailsView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - // implementation note: the horizonal position is ignored currently, as no - // horizontal scrolling is done anyway during a selection - const QScrollBar* scrollbar = verticalScrollBar(); - Q_ASSERT(scrollbar != 0); + removeExpandedIndexes(parent, start, end); + QTreeView::rowsAboutToBeRemoved(parent, start, end); +} - const int maxHeight = maximumViewportSize().height(); - const int height = scrollbar->maximum() - scrollbar->minimum() + 1; - const int visibleHeight = model()->rowCount() + 1 - height; - if (visibleHeight <= 0) { - return QPoint(0, 0); +void DolphinDetailsView::removeExpandedIndexes(const QModelIndex& parent, int start, int end) +{ + if (m_expandedUrls.isEmpty()) { + return; } - const int y = scrollbar->sliderPosition() * maxHeight / visibleHeight; - return QPoint(0, y); + for (int row = start; row <= end; row++) { + const QModelIndex index = model()->index(row, 0, parent); + if (isExpanded(index)) { + slotCollapsed(index); + removeExpandedIndexes(index, 0, model()->rowCount(index) - 1); + } + } +} + +void DolphinDetailsView::updateDecorationSize(bool showPreview) +{ + DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); + const int iconSize = showPreview ? settings->previewSize() : settings->iconSize(); + setIconSize(QSize(iconSize, iconSize)); + m_decorationSize = QSize(iconSize, iconSize); + + doItemsLayout(); } KFileItemDelegate::Information DolphinDetailsView::infoForColumn(int columnIndex) const @@ -888,13 +991,14 @@ void DolphinDetailsView::resizeColumns() QHeaderView* headerView = header(); QFontMetrics fontMetrics(viewport()->font()); - int columnWidth[KDirModel::ColumnCount]; - columnWidth[KDirModel::Size] = fontMetrics.width("00000 Items"); - columnWidth[KDirModel::ModifiedTime] = fontMetrics.width("0000-00-00 00:00"); - columnWidth[KDirModel::Permissions] = fontMetrics.width("xxxxxxxxxx"); - columnWidth[KDirModel::Owner] = fontMetrics.width("xxxxxxxxxx"); - columnWidth[KDirModel::Group] = fontMetrics.width("xxxxxxxxxx"); - columnWidth[KDirModel::Type] = fontMetrics.width("XXXX Xxxxxxx"); + int columnWidth[DolphinModel::Version + 1]; + columnWidth[DolphinModel::Size] = fontMetrics.width("00000 Items"); + columnWidth[DolphinModel::ModifiedTime] = fontMetrics.width("0000-00-00 00:00"); + columnWidth[DolphinModel::Permissions] = fontMetrics.width("xxxxxxxxxx"); + columnWidth[DolphinModel::Owner] = fontMetrics.width("xxxxxxxxxx"); + columnWidth[DolphinModel::Group] = fontMetrics.width("xxxxxxxxxx"); + columnWidth[DolphinModel::Type] = fontMetrics.width("XXXX Xxxxxxx"); + columnWidth[DolphinModel::Version] = fontMetrics.width("xxxxxxxx"); int requiredWidth = 0; for (int i = KDirModel::Size; i <= KDirModel::Type; ++i) { @@ -907,22 +1011,55 @@ void DolphinDetailsView::resizeColumns() // resize the name column in a way that the whole available width is used columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth; - if (columnWidth[KDirModel::Name] < 120) { - columnWidth[KDirModel::Name] = 120; + + const int minNameWidth = 300; + if (columnWidth[KDirModel::Name] < minNameWidth) { + columnWidth[KDirModel::Name] = minNameWidth; + + // It might be possible that the name column width can be + // decreased without clipping any text. For performance + // reasons the exact necessary width for full visible names is + // only checked for up to 200 items: + const int rowCount = model()->rowCount(); + if (rowCount > 0 && rowCount < 200) { + const int nameWidth = sizeHintForColumn(DolphinModel::Name); + if (nameWidth + requiredWidth <= viewport()->width()) { + columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth; + } else if (nameWidth < minNameWidth) { + columnWidth[KDirModel::Name] = nameWidth; + } + } } + headerView->resizeSection(KDirModel::Name, columnWidth[KDirModel::Name]); } -QRect DolphinDetailsView::nameColumnRect(const QModelIndex& index) const +bool DolphinDetailsView::isAboveExpandingToggle(const QPoint& pos) const { - QRect rect = visualRect(index); - const KFileItem item = m_controller->itemForIndex(index); - if (!item.isNull()) { - const int width = DolphinFileItemDelegate::nameColumnWidth(item.text(), viewOptions()); - rect.setWidth(width); - } + // QTreeView offers no public API to get the information whether an index has an + // expanding toggle and what boundaries the toggle has. The following approach + // also assumes a toggle for file items. + if (itemsExpandable()) { + const QModelIndex index = QTreeView::indexAt(pos); + if (index.isValid() && (index.column() == KDirModel::Name)) { + QRect rect = visualRect(index); + const int toggleSize = rect.height(); + if (isRightToLeft()) { + rect.moveRight(rect.right()); + } else { + rect.moveLeft(rect.x() - toggleSize); + } + rect.setWidth(toggleSize); - return rect; + QStyleOption opt; + opt.initFrom(this); + opt.rect = rect; + rect = style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, this); + + return rect.contains(pos); + } + } + return false; } DolphinDetailsView::ElasticBand::ElasticBand() :