From 3f88f79f862a570b68fe64781955cf7d14124127 Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Fri, 23 Mar 2012 22:26:17 +0100 Subject: Details view: Optionally remember user changed column-widths If the user changed a column-width in the details-view, up to now the width got reset when changing a directory or when restarting Dolphin. Now the column-widths automatically get remembered for each directory in case if the user has modified the width. The automatic resizing is still turn on per default. The storing of the custom column-width can easily be reset by right clicking on the header and selecting "Automatic Column Widths" from the context-menu. Some finetuning is still necessary (e.g. the "Adjust View Properties" dialog currently is not aware about this setting) but this will be fixed during the next weeks. BUG: 264434 FIXED-IN: 4.9.0 --- src/kitemviews/kitemlistview.cpp | 283 ++++++++++++++++++++------------------- 1 file changed, 147 insertions(+), 136 deletions(-) (limited to 'src/kitemviews/kitemlistview.cpp') diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 0880687e1..ff1cbc39a 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -23,7 +23,8 @@ #include "kitemlistview.h" #include "kitemlistcontroller.h" -#include "kitemlistheader_p.h" +#include "kitemlistheader.h" +#include "kitemlistheaderwidget_p.h" #include "kitemlistrubberband_p.h" #include "kitemlistselectionmanager.h" #include "kitemlistsizehintresolver_p.h" @@ -61,13 +62,12 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : m_controller(0), m_model(0), m_visibleRoles(), - m_visibleRolesSizes(), - m_stretchedVisibleRolesSizes(), m_widgetCreator(0), m_groupHeaderCreator(0), m_styleOption(), m_visibleItems(), m_visibleGroups(), + m_columnWidthsCache(), m_visibleCells(), m_sizeHintResolver(0), m_layouter(0), @@ -83,7 +83,7 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : m_autoScrollIncrement(0), m_autoScrollTimer(0), m_header(0), - m_useHeaderWidths(false) + m_headerWidget(0) { setAcceptHoverEvents(true); @@ -103,6 +103,11 @@ KItemListView::KItemListView(QGraphicsWidget* parent) : m_rubberBand = new KItemListRubberBand(this); connect(m_rubberBand, SIGNAL(activationChanged(bool)), this, SLOT(slotRubberBandActivationChanged(bool))); + + m_headerWidget = new KItemListHeaderWidget(this); + m_headerWidget->setVisible(false); + + m_header = new KItemListHeader(this); } KItemListView::~KItemListView() @@ -171,7 +176,15 @@ void KItemListView::setItemSize(const QSizeF& itemSize) } if (itemSize.isEmpty()) { - updateVisibleRolesSizes(); + if (m_headerWidget->automaticColumnResizing()) { + updateColumnWidthsCache(); + } else { + // Only apply the changed height and respect the header widths + // set by the user + const qreal currentWidth = m_layouter->itemSize().width(); + const QSizeF newSize(currentWidth, itemSize.height()); + m_layouter->setItemSize(newSize); + } } else { m_layouter->setItemSize(itemSize); } @@ -224,8 +237,8 @@ void KItemListView::setItemOffset(qreal offset) } m_layouter->setItemOffset(offset); - if (m_header) { - m_header->setPos(-offset, 0); + if (m_headerWidget->isVisible()) { + m_headerWidget->setPos(-offset, 0); } // Don't check whether the m_layoutTimer is active: Changing the @@ -258,7 +271,7 @@ void KItemListView::setVisibleRoles(const QList& roles) it.next(); KItemListWidget* widget = it.value(); widget->setVisibleRoles(roles); - widget->setVisibleRolesSizes(m_stretchedVisibleRolesSizes); + updateWidgetColumnWidths(widget); if (alternateBackgroundsChanged) { updateAlternateBackgroundForWidget(widget); } @@ -267,13 +280,12 @@ void KItemListView::setVisibleRoles(const QList& roles) m_sizeHintResolver->clearCache(); m_layouter->markAsDirty(); - if (m_header) { - m_header->setVisibleRoles(roles); - m_header->setVisibleRolesWidths(headerRolesWidths()); - m_useHeaderWidths = false; + if (m_headerWidget->isVisible()) { + m_headerWidget->setColumns(roles); + m_headerWidget->setAutomaticColumnResizing(true); } - updateVisibleRolesSizes(); + updateColumnWidthsCache(); doLayout(NoAnimation); onVisibleRolesChanged(roles, previousRoles); @@ -402,26 +414,18 @@ void KItemListView::setGeometry(const QRectF& rect) // Changing the geometry does not require to do an expensive // update of the visible-roles sizes, only the stretched sizes // need to be adjusted to the new size. - updateStretchedVisibleRolesSizes(); + updateColumnWidthsForHeader(); - if (m_useHeaderWidths) { + if (!m_headerWidget->automaticColumnResizing()) { QSizeF dynamicItemSize = m_layouter->itemSize(); if (m_itemSize.width() < 0) { - const qreal requiredWidth = visibleRolesSizesWidthSum(); + const qreal requiredWidth = columnWidthsSum(); if (newSize.width() > requiredWidth) { dynamicItemSize.setWidth(newSize.width()); } const qreal headerWidth = qMax(newSize.width(), requiredWidth); - m_header->resize(headerWidth, m_header->size().height()); - } - - if (m_itemSize.height() < 0) { - const qreal requiredHeight = visibleRolesSizesHeightSum(); - if (newSize.height() > requiredHeight) { - dynamicItemSize.setHeight(newSize.height()); - } - // TODO: KItemListHeader is not prepared for vertical alignment + m_headerWidget->resize(headerWidth, m_headerWidget->size().height()); } m_layouter->setItemSize(dynamicItemSize); @@ -513,10 +517,10 @@ QSizeF KItemListView::itemSizeHint(int index) const return itemSize(); } -QHash KItemListView::visibleRolesSizes(const KItemRangeList& itemRanges) const +QHash KItemListView::columnWidths(const KItemRangeList& itemRanges) const { Q_UNUSED(itemRanges); - return QHash(); + return QHash(); } void KItemListView::setSupportsItemExpanding(bool supportsExpanding) @@ -554,8 +558,8 @@ QRectF KItemListView::itemContextRect(int index) const void KItemListView::scrollToItem(int index) { QRectF viewGeometry = geometry(); - if (m_header) { - const qreal headerHeight = m_header->size().height(); + if (m_headerWidget->isVisible()) { + const qreal headerHeight = m_headerWidget->size().height(); viewGeometry.adjust(0, headerHeight, 0, 0); } const QRectF currentRect = itemRect(index); @@ -610,40 +614,52 @@ bool KItemListView::isTransactionActive() const return m_activeTransactions > 0; } -void KItemListView::setHeaderShown(bool show) +void KItemListView::setHeaderVisible(bool visible) { - if (show && !m_header) { - m_header = new KItemListHeader(this); - m_header->setPos(0, 0); - m_header->setModel(m_model); - m_header->setVisibleRoles(m_visibleRoles); - m_header->setVisibleRolesWidths(headerRolesWidths()); - m_header->setZValue(1); + if (visible && !m_headerWidget->isVisible()) { + m_headerWidget->setPos(0, 0); + m_headerWidget->setModel(m_model); + m_headerWidget->setColumns(m_visibleRoles); + m_headerWidget->setZValue(1); - connect(m_header, SIGNAL(visibleRoleWidthChanged(QByteArray,qreal,qreal)), - this, SLOT(slotVisibleRoleWidthChanged(QByteArray,qreal,qreal))); - connect(m_header, SIGNAL(visibleRoleMoved(QByteArray,int,int)), - this, SLOT(slotVisibleRoleMoved(QByteArray,int,int))); - connect(m_header, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), + connect(m_headerWidget, SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)), + this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal))); + connect(m_headerWidget, SIGNAL(columnMoved(QByteArray,int,int)), + this, SLOT(slotHeaderColumnMoved(QByteArray,int,int))); + connect(m_headerWidget, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), this, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder))); - connect(m_header, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), + connect(m_headerWidget, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), this, SIGNAL(sortRoleChanged(QByteArray,QByteArray))); - m_useHeaderWidths = false; + m_headerWidget->setAutomaticColumnResizing(true); + + m_layouter->setHeaderHeight(m_headerWidget->size().height()); + m_headerWidget->setVisible(true); + } else if (!visible && m_headerWidget->isVisible()) { + disconnect(m_headerWidget, SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)), + this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal))); + disconnect(m_headerWidget, SIGNAL(columnMoved(QByteArray,int,int)), + this, SLOT(slotHeaderColumnMoved(QByteArray,int,int))); + disconnect(m_headerWidget, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), + this, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder))); + disconnect(m_headerWidget, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), + this, SIGNAL(sortRoleChanged(QByteArray,QByteArray))); - m_layouter->setHeaderHeight(m_header->size().height()); - } else if (!show && m_header) { - delete m_header; - m_header = 0; - m_useHeaderWidths = false; m_layouter->setHeaderHeight(0); + m_headerWidget->setAutomaticColumnResizing(true); + m_headerWidget->setVisible(false); } } -bool KItemListView::isHeaderShown() const +bool KItemListView::isHeaderVisible() const { - return m_header != 0; + return m_headerWidget->isVisible(); +} + +KItemListHeader* KItemListView::header() const +{ + return m_header; } QPixmap KItemListView::createDragPixmap(const QSet& indexes) const @@ -803,7 +819,7 @@ QList KItemListView::visibleItemListWidgets() const void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) { - updateVisibleRolesSizes(itemRanges); + updateColumnWidthsCache(itemRanges); const bool hasMultipleRanges = (itemRanges.count() > 1); if (hasMultipleRanges) { @@ -902,7 +918,7 @@ void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges) { - updateVisibleRolesSizes(); + updateColumnWidthsCache(); const bool hasMultipleRanges = (itemRanges.count() > 1); if (hasMultipleRanges) { @@ -1034,7 +1050,7 @@ void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, { const bool updateSizeHints = itemSizeHintUpdateRequired(roles); if (updateSizeHints) { - updateVisibleRolesSizes(itemRanges); + updateColumnWidthsCache(itemRanges); } foreach (const KItemRange& itemRange, itemRanges) { @@ -1206,46 +1222,36 @@ void KItemListView::slotRubberBandActivationChanged(bool active) update(); } -void KItemListView::slotVisibleRoleWidthChanged(const QByteArray& role, - qreal currentWidth, - qreal previousWidth) +void KItemListView::slotHeaderColumnWidthChanged(const QByteArray& role, + qreal currentWidth, + qreal previousWidth) { Q_UNUSED(previousWidth); - m_useHeaderWidths = true; + m_headerWidget->setAutomaticColumnResizing(false); - if (m_visibleRolesSizes.contains(role)) { - QSizeF roleSize = m_visibleRolesSizes.value(role); - roleSize.setWidth(currentWidth); - m_visibleRolesSizes.insert(role, roleSize); - m_stretchedVisibleRolesSizes.insert(role, roleSize); + if (m_columnWidthsCache.contains(role)) { + m_columnWidthsCache.insert(role, currentWidth); // Apply the new size to the layouter - QSizeF dynamicItemSize = m_itemSize; - if (dynamicItemSize.width() < 0) { - const qreal requiredWidth = visibleRolesSizesWidthSum(); - dynamicItemSize.setWidth(qMax(size().width(), requiredWidth)); - } - if (dynamicItemSize.height() < 0) { - const qreal requiredHeight = visibleRolesSizesHeightSum(); - dynamicItemSize.setHeight(qMax(size().height(), requiredHeight)); - } - + const qreal requiredWidth = columnWidthsSum(); + const QSizeF dynamicItemSize(qMax(size().width(), requiredWidth), + m_itemSize.height()); m_layouter->setItemSize(dynamicItemSize); // Update the role sizes for all visible widgets QHashIterator it(m_visibleItems); while (it.hasNext()) { it.next(); - it.value()->setVisibleRolesSizes(m_stretchedVisibleRolesSizes); + updateWidgetColumnWidths(it.value()); } doLayout(NoAnimation); } } -void KItemListView::slotVisibleRoleMoved(const QByteArray& role, - int currentIndex, - int previousIndex) +void KItemListView::slotHeaderColumnMoved(const QByteArray& role, + int currentIndex, + int previousIndex) { Q_ASSERT(m_visibleRoles[previousIndex] == role); @@ -1743,7 +1749,7 @@ void KItemListView::setLayouterSize(const QSizeF& size, SizeType sizeType) void KItemListView::updateWidgetProperties(KItemListWidget* widget, int index) { widget->setVisibleRoles(m_visibleRoles); - widget->setVisibleRolesSizes(m_stretchedVisibleRolesSizes); + updateWidgetColumnWidths(widget); widget->setStyleOption(m_styleOption); const KItemListSelectionManager* selectionManager = m_controller->selectionManager(); @@ -1907,22 +1913,39 @@ bool KItemListView::useAlternateBackgrounds() const return m_itemSize.isEmpty() && m_visibleRoles.count() > 1; } -QHash KItemListView::headerRolesWidths() const +void KItemListView::applyColumnWidthsFromHeader() { - QHash rolesWidths; + qreal roleWidthSum = 0; + foreach (const QByteArray& role, m_visibleRoles) { + const qreal width = m_headerWidget->columnWidth(role); + m_columnWidthsCache.insert(role, width); + roleWidthSum += width; + } + + // Apply the new size to the layouter + const QSizeF dynamicItemSize(qMax(size().width(), roleWidthSum), + m_itemSize.height()); + m_layouter->setItemSize(dynamicItemSize); - QHashIterator it(m_stretchedVisibleRolesSizes); + // Update the role sizes for all visible widgets + QHashIterator it(m_visibleItems); while (it.hasNext()) { it.next(); - rolesWidths.insert(it.key(), it.value().width()); + updateWidgetColumnWidths(it.value()); } + doLayout(NoAnimation); +} - return rolesWidths; +void KItemListView::updateWidgetColumnWidths(KItemListWidget* widget) +{ + foreach (const QByteArray& role, m_visibleRoles) { + widget->setColumnWidth(role, m_headerWidget->columnWidth(role)); + } } -void KItemListView::updateVisibleRolesSizes(const KItemRangeList& itemRanges) +void KItemListView::updateColumnWidthsCache(const KItemRangeList& itemRanges) { - if (!m_itemSize.isEmpty() || m_useHeaderWidths) { + if (!m_itemSize.isEmpty() || !m_headerWidget->automaticColumnResizing()) { return; } @@ -1933,37 +1956,35 @@ void KItemListView::updateVisibleRolesSizes(const KItemRangeList& itemRanges) } if (itemCount == rangesItemCount) { - m_visibleRolesSizes = visibleRolesSizes(itemRanges); - if (m_header) { + m_columnWidthsCache = columnWidths(itemRanges); + if (m_headerWidget->isVisible()) { // Assure the the sizes are not smaller than the minimum defined by the header - // TODO: Currently only implemented for a top-aligned header - const qreal minHeaderRoleWidth = m_header->minimumRoleWidth(); - QMutableHashIterator it (m_visibleRolesSizes); + const qreal minHeaderRoleWidth = m_headerWidget->minimumColumnWidth(); + QMutableHashIterator it (m_columnWidthsCache); while (it.hasNext()) { it.next(); - const QSizeF& size = it.value(); - if (size.width() < minHeaderRoleWidth) { - const QSizeF newSize(minHeaderRoleWidth, size.height()); - m_visibleRolesSizes.insert(it.key(), newSize); + const qreal width = it.value(); + if (width < minHeaderRoleWidth) { + m_columnWidthsCache.insert(it.key(), minHeaderRoleWidth); } } } } else { // Only a sub range of the roles need to be determined. - // The chances are good that the sizes of the sub ranges - // already fit into the available sizes and hence no + // The chances are good that the widths of the sub ranges + // already fit into the available widths and hence no // expensive update might be required. bool updateRequired = false; - const QHash updatedSizes = visibleRolesSizes(itemRanges); - QHashIterator it(updatedSizes); + const QHash updatedWidths = columnWidths(itemRanges); + QHashIterator it(updatedWidths); while (it.hasNext()) { it.next(); const QByteArray& role = it.key(); - const QSizeF& updatedSize = it.value(); - const QSizeF currentSize = m_visibleRolesSizes.value(role); - if (updatedSize.width() > currentSize.width() || updatedSize.height() > currentSize.height()) { - m_visibleRolesSizes.insert(role, updatedSize); + const qreal updatedWidth = it.value(); + const qreal currentWidth = m_columnWidthsCache.value(role); + if (updatedWidth > currentWidth) { + m_columnWidthsCache.insert(role, updatedWidth); updateRequired = true; } } @@ -1975,10 +1996,10 @@ void KItemListView::updateVisibleRolesSizes(const KItemRangeList& itemRanges) } } - updateStretchedVisibleRolesSizes(); + updateColumnWidthsForHeader(); } -void KItemListView::updateVisibleRolesSizes() +void KItemListView::updateColumnWidthsCache() { if (!m_model) { return; @@ -1986,13 +2007,13 @@ void KItemListView::updateVisibleRolesSizes() const int itemCount = m_model->count(); if (itemCount > 0) { - updateVisibleRolesSizes(KItemRangeList() << KItemRange(0, itemCount)); + updateColumnWidthsCache(KItemRangeList() << KItemRange(0, itemCount)); } } -void KItemListView::updateStretchedVisibleRolesSizes() +void KItemListView::updateColumnWidthsForHeader() { - if (!m_itemSize.isEmpty() || m_useHeaderWidths || m_visibleRoles.isEmpty()) { + if (!m_itemSize.isEmpty() || !m_headerWidget->automaticColumnResizing() || m_visibleRoles.isEmpty()) { return; } @@ -2000,74 +2021,64 @@ void KItemListView::updateStretchedVisibleRolesSizes() // visible role sizes and apply them to the layouter. If the // size does not use the available view-size the size of the // first role will get stretched. - m_stretchedVisibleRolesSizes = m_visibleRolesSizes; + + foreach (const QByteArray& role, m_visibleRoles) { + m_headerWidget->setColumnWidth(role, m_columnWidthsCache.value(role)); + } + const QByteArray role = m_visibleRoles.first(); - QSizeF firstRoleSize = m_stretchedVisibleRolesSizes.value(role); + qreal firstColumnWidth = m_columnWidthsCache.value(role); QSizeF dynamicItemSize = m_itemSize; if (dynamicItemSize.width() <= 0) { - const qreal requiredWidth = visibleRolesSizesWidthSum(); + const qreal requiredWidth = columnWidthsSum(); const qreal availableWidth = size().width(); if (requiredWidth != availableWidth) { // Stretch the first role to use the whole remaining width - firstRoleSize.rwidth() += availableWidth - requiredWidth; + firstColumnWidth += availableWidth - requiredWidth; // TODO: A proper calculation of the minimum width depends on the implementation // of KItemListWidget. Probably a kind of minimum size-hint should be introduced // later. const qreal minWidth = m_styleOption.iconSize * 2 + 200; - if (firstRoleSize.width() < minWidth) { - firstRoleSize.rwidth() = minWidth; + if (firstColumnWidth < minWidth) { + firstColumnWidth = minWidth; } - m_stretchedVisibleRolesSizes.insert(role, firstRoleSize); + + m_headerWidget->setColumnWidth(role, firstColumnWidth); } dynamicItemSize.rwidth() = qMax(requiredWidth, availableWidth); } - // TODO: A dynamic item height (dynamicItemSize.height() <= 0) - // is not handled currently - m_layouter->setItemSize(dynamicItemSize); - if (m_header) { - m_header->setVisibleRolesWidths(headerRolesWidths()); - m_header->resize(dynamicItemSize.width(), m_header->size().height()); + if (m_headerWidget->isVisible()) { + m_headerWidget->resize(dynamicItemSize.width(), m_headerWidget->size().height()); } // Update the role sizes for all visible widgets QHashIterator it(m_visibleItems); while (it.hasNext()) { it.next(); - it.value()->setVisibleRolesSizes(m_stretchedVisibleRolesSizes); + updateWidgetColumnWidths(it.value()); } } -qreal KItemListView::visibleRolesSizesWidthSum() const +qreal KItemListView::columnWidthsSum() const { qreal widthSum = 0; - QHashIterator it(m_visibleRolesSizes); + QHashIterator it(m_columnWidthsCache); while (it.hasNext()) { it.next(); - widthSum += it.value().width(); + widthSum += it.value(); } return widthSum; } -qreal KItemListView::visibleRolesSizesHeightSum() const -{ - qreal heightSum = 0; - QHashIterator it(m_visibleRolesSizes); - while (it.hasNext()) { - it.next(); - heightSum += it.value().height(); - } - return heightSum; -} - QRectF KItemListView::headerBoundaries() const { - return m_header ? m_header->geometry() : QRectF(); + return m_headerWidget->isVisible() ? m_headerWidget->geometry() : QRectF(); } bool KItemListView::changesItemGridLayout(const QSizeF& newGridSize, -- cgit v1.3