]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Details view: Optionally remember user changed column-widths
authorPeter Penz <peter.penz19@gmail.com>
Fri, 23 Mar 2012 21:26:17 +0000 (22:26 +0100)
committerPeter Penz <peter.penz19@gmail.com>
Fri, 23 Mar 2012 21:31:55 +0000 (22:31 +0100)
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

19 files changed:
src/CMakeLists.txt
src/kitemviews/kfileitemlistview.cpp
src/kitemviews/kfileitemlistview.h
src/kitemviews/kfileitemlistwidget.cpp
src/kitemviews/kfileitemlistwidget.h
src/kitemviews/kitemlistheader.cpp
src/kitemviews/kitemlistheader.h [new file with mode: 0644]
src/kitemviews/kitemlistheaderwidget.cpp [new file with mode: 0644]
src/kitemviews/kitemlistheaderwidget_p.h [moved from src/kitemviews/kitemlistheader_p.h with 78% similarity]
src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h
src/kitemviews/kitemlistwidget.cpp
src/kitemviews/kitemlistwidget.h
src/settings/dolphin_directoryviewpropertysettings.kcfg
src/views/dolphinitemlistcontainer.cpp
src/views/dolphinview.cpp
src/views/dolphinview.h
src/views/viewproperties.cpp
src/views/viewproperties.h

index 39fd94aa07b9a93c3e7f249182ca777f8236b3ce..2ab5e9cdda99f70161c411ed5ad92804e569ea1c 100644 (file)
@@ -29,6 +29,7 @@ set(dolphinprivate_LIB_SRCS
     kitemviews/kitemlistcontroller.cpp
     kitemviews/kitemlistgroupheader.cpp
     kitemviews/kitemlistheader.cpp
+    kitemviews/kitemlistheaderwidget.cpp
     kitemviews/kitemlistkeyboardsearchmanager.cpp
     kitemviews/kitemlistrubberband.cpp
     kitemviews/kitemlistselectionmanager.cpp
index 54d858c1e5ba34c3fe2aee47fd1dfe0124351689..483dabb8366f13b6d3de8a8df021f1141f876bf1 100644 (file)
@@ -193,12 +193,12 @@ QSizeF KFileItemListView::itemSizeHint(int index) const
     return QSize();
 }
 
-QHash<QByteArray, QSizeF> KFileItemListView::visibleRolesSizes(const KItemRangeList& itemRanges) const
+QHash<QByteArray, qreal> KFileItemListView::columnWidths(const KItemRangeList& itemRanges) const
 {
     QElapsedTimer timer;
     timer.start();
 
-    QHash<QByteArray, QSizeF> sizes;
+    QHash<QByteArray, qreal> widths;
 
     int calculatedItemCount = 0;
     bool maxTimeExceeded = false;
@@ -208,10 +208,10 @@ QHash<QByteArray, QSizeF> KFileItemListView::visibleRolesSizes(const KItemRangeL
 
         for (int i = startIndex; i <= endIndex; ++i) {
             foreach (const QByteArray& visibleRole, visibleRoles()) {
-                QSizeF maxSize = sizes.value(visibleRole, QSizeF(0, 0));
+                qreal maxWidth = widths.value(visibleRole, 0);
                 const QSizeF itemSize = visibleRoleSizeHint(i, visibleRole);
-                maxSize = maxSize.expandedTo(itemSize);
-                sizes.insert(visibleRole, maxSize);
+                maxWidth = qMax(itemSize.width(), maxWidth);
+                widths.insert(visibleRole, maxWidth);
             }
 
             if (calculatedItemCount > 100 && timer.elapsed() > 200) {
@@ -238,7 +238,7 @@ QHash<QByteArray, QSizeF> KFileItemListView::visibleRolesSizes(const KItemRangeL
     }
     kDebug() << "[TIME] Calculated dynamic item size for " << rangesItemCount << "items:" << timer.elapsed();
 #endif
-    return sizes;
+    return widths;
 }
 
 QPixmap KFileItemListView::createDragPixmap(const QSet<int>& indexes) const
index 12d0d452b21cd53323563c1aaf6d220e3dd0a224..23a84d4b96547cdc75a713c90c19f78826901268 100644 (file)
@@ -78,7 +78,7 @@ public:
     virtual QSizeF itemSizeHint(int index) const;
 
     /** @reimp */
-    virtual QHash<QByteArray, QSizeF> visibleRolesSizes(const KItemRangeList& itemRanges) const;
+    virtual QHash<QByteArray, qreal> columnWidths(const KItemRangeList& itemRanges) const;
 
     /** @reimp */
     virtual QPixmap createDragPixmap(const QSet<int>& indexes) const;
index fb0f4df5798f69eba0a4ae8e4e9d8caa6072533d..5c865d1ca3a0f7872b6eaa92a6631f5417c9d380 100644 (file)
@@ -139,7 +139,7 @@ void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsIte
         // with the icon. This can happen if the user has minimized the width
         // of the name-column to a very small value.
         const qreal minX = m_pixmapPos.x() + m_pixmap.width() + 4 * itemListStyleOption.padding;
-        if (m_textPos[Name + 1].x() < minX) {
+        if (m_textPos[Name].x() + columnWidth("name") > minX) {
             clipAdditionalInfoBounds = true;
             painter->save();
             painter->setClipRect(minX, 0, size().width() - minX, size().height(), Qt::IntersectClip);
@@ -347,9 +347,11 @@ void KFileItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
     m_dirtyLayout = true;
 }
 
-void KFileItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current,
-                                                   const QHash<QByteArray, QSizeF>& previous)
+void KFileItemListWidget::columnWidthChanged(const QByteArray& role,
+                                             qreal current,
+                                             qreal previous)
 {
+    Q_UNUSED(role);
     Q_UNUSED(current);
     Q_UNUSED(previous);
     m_dirtyLayout = true;
@@ -783,8 +785,8 @@ void KFileItemListWidget::updateDetailsLayoutTextCache()
 
         // Elide the text in case it does not fit into the available column-width
         qreal requiredWidth = option.fontMetrics.width(text);
-        const qreal columnWidth = visibleRolesSizes().value(role, QSizeF(0, 0)).width();
-        qreal availableTextWidth = columnWidth - 2 * columnPadding;
+        const qreal roleWidth = columnWidth(role);
+        qreal availableTextWidth = roleWidth - 2 * columnPadding;
         if (textId == Name) {
             availableTextWidth -= firstColumnInc;
         }
@@ -796,7 +798,7 @@ void KFileItemListWidget::updateDetailsLayoutTextCache()
 
         m_text[textId].setText(text);
         m_textPos[textId] = QPointF(x + columnPadding, y);
-        x += columnWidth;
+        x += roleWidth;
 
         switch (textId) {
         case Name: {
@@ -813,7 +815,7 @@ void KFileItemListWidget::updateDetailsLayoutTextCache()
         }
         case Size:
             // The values for the size should be right aligned
-            m_textPos[textId].rx() += columnWidth - requiredWidth - 2 * columnPadding;
+            m_textPos[textId].rx() += roleWidth - requiredWidth - 2 * columnPadding;
             break;
 
         default:
index 4958313356d8dc56f5a6441e2cddb4d0d5c571d0..3e6cf8d2ab0f9f1cda8fce3ed20b55bb2afeb9fd 100644 (file)
@@ -85,7 +85,7 @@ protected:
 
     virtual void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>());
     virtual void visibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous);
-    virtual void visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current, const QHash<QByteArray, QSizeF>& previous);
+    virtual void columnWidthChanged(const QByteArray& role, qreal current, qreal previous);
     virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
     virtual void hoveredChanged(bool hovered);
     virtual void selectedChanged(bool selected);
index ea714c96fc7d1e400728304d3efadb1a28d9c808..f1050538d3290f79b39d33282f6e7dd4a40089df 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
+ *   Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com>             *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
  ***************************************************************************/
 
-#include "kitemlistheader_p.h"
-
-#include <KAction>
-#include <KMenu>
-#include "kitemmodelbase.h"
-
-#include <QApplication>
-#include <QGraphicsSceneHoverEvent>
-#include <QPainter>
-#include <QStyleOptionHeader>
-
-#include <KDebug>
-
-KItemListHeader::KItemListHeader(QGraphicsWidget* parent) :
-    QGraphicsWidget(parent),
-    m_model(0),
-    m_visibleRoles(),
-    m_visibleRolesWidths(),
-    m_hoveredRoleIndex(-1),
-    m_pressedRoleIndex(-1),
-    m_roleOperation(NoRoleOperation),
-    m_pressedMousePos(),
-    m_movingRole()
-{
-    m_movingRole.x = 0;
-    m_movingRole.xDec = 0;
-    m_movingRole.index = -1;
-
-    setAcceptHoverEvents(true);
-
-    QStyleOptionHeader option;
-    const QSize headerSize = style()->sizeFromContents(QStyle::CT_HeaderSection, &option, QSize());
-    resize(0, headerSize.height());
-}
+#include "kitemlistheader.h"
+#include "kitemlistheaderwidget_p.h"
+#include "kitemlistview.h"
 
 KItemListHeader::~KItemListHeader()
 {
 }
 
-void KItemListHeader::setModel(KItemModelBase* model)
-{
-    if (m_model == model) {
-        return;
-    }
-
-    if (m_model) {
-        disconnect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
-                   this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
-        disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
-                   this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
-    }
-
-    m_model = model;
-
-    if (m_model) {
-        connect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
-                this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
-        connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
-                this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
-    }
-}
-
-KItemModelBase* KItemListHeader::model() const
-{
-    return m_model;
-}
-
-void KItemListHeader::setVisibleRoles(const QList<QByteArray>& roles)
-{
-    m_visibleRoles = roles;
-    update();
-}
-
-QList<QByteArray> KItemListHeader::visibleRoles() const
-{
-    return m_visibleRoles;
-}
-
-void KItemListHeader::setVisibleRolesWidths(const QHash<QByteArray, qreal>& rolesWidths)
-{
-    m_visibleRolesWidths = rolesWidths;
-
-    // Assure that no width is smaller than the minimum allowed width
-    const qreal minWidth = minimumRoleWidth();
-    QMutableHashIterator<QByteArray, qreal> it(m_visibleRolesWidths);
-    while (it.hasNext()) {
-        it.next();
-        if (it.value() < minWidth) {
-            m_visibleRolesWidths.insert(it.key(), minWidth);
-        }
-    }
-
-    update();
-}
-
-QHash<QByteArray, qreal> KItemListHeader::visibleRolesWidths() const
-{
-    return m_visibleRolesWidths;
-}
-
-qreal KItemListHeader::minimumRoleWidth() const
-{
-    QFontMetricsF fontMetrics(font());
-    return fontMetrics.height() * 4;
-}
-
-void KItemListHeader::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
-{
-    Q_UNUSED(option);
-    Q_UNUSED(widget);
-
-    if (!m_model) {
-        return;
-    }
-
-    // Draw roles
-    painter->setFont(font());
-    painter->setPen(palette().text().color());
-
-    qreal x = 0;
-    int orderIndex = 0;
-    foreach (const QByteArray& role, m_visibleRoles) {
-        const qreal roleWidth = m_visibleRolesWidths.value(role);
-        const QRectF rect(x, 0, roleWidth, size().height());
-        paintRole(painter, role, rect, orderIndex, widget);
-        x += roleWidth;
-        ++orderIndex;
-    }
-
-    // Draw background without roles
-    QStyleOption opt;
-    opt.init(widget);
-    opt.rect = QRect(x, 0, size().width() - x, size().height());
-    opt.state |= QStyle::State_Horizontal;
-    style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, painter);
-
-    if (!m_movingRole.pixmap.isNull()) {
-        Q_ASSERT(m_roleOperation == MoveRoleOperation);
-        painter->drawPixmap(m_movingRole.x, 0, m_movingRole.pixmap);
-    }
-}
-
-void KItemListHeader::mousePressEvent(QGraphicsSceneMouseEvent* event)
-{
-    if (event->button() & Qt::LeftButton) {
-        updatePressedRoleIndex(event->pos());
-        m_pressedMousePos = event->pos();
-        m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ?
-                          ResizeRoleOperation : NoRoleOperation;
-        event->accept();
-    } else {
-        event->ignore();
-    }
-}
-
-void KItemListHeader::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
+void KItemListHeader::setAutomaticColumnResizing(bool automatic)
 {
-    QGraphicsWidget::mouseReleaseEvent(event);
-
-    if (m_pressedRoleIndex == -1) {
-        return;
-    }
-
-    switch (m_roleOperation) {
-    case NoRoleOperation: {
-        // Only a click has been done and no moving or resizing has been started
-        const QByteArray sortRole = m_model->sortRole();
-        const int sortRoleIndex = m_visibleRoles.indexOf(sortRole);
-        if (m_pressedRoleIndex == sortRoleIndex) {
-            // Toggle the sort order
-            const Qt::SortOrder previous = m_model->sortOrder();
-            const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ?
-                                          Qt::DescendingOrder : Qt::AscendingOrder;
-            m_model->setSortOrder(current);
-            emit sortOrderChanged(current, previous);
-        } else {
-            // Change the sort role
-            const QByteArray previous = m_model->sortRole();
-            const QByteArray current = m_visibleRoles[m_pressedRoleIndex];
-            m_model->setSortRole(current);
-            emit sortRoleChanged(current, previous);
-        }
-        break;
-    }
-
-    case MoveRoleOperation:
-        m_movingRole.pixmap = QPixmap();
-        m_movingRole.x = 0;
-        m_movingRole.xDec = 0;
-        m_movingRole.index = -1;
-        break;
-
-    default:
-        break;
-    }
-
-    m_pressedRoleIndex = -1;
-    m_roleOperation = NoRoleOperation;
-    update();
-
-    QApplication::restoreOverrideCursor();
-}
-
-void KItemListHeader::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
-{
-    QGraphicsWidget::mouseMoveEvent(event);
-
-    switch (m_roleOperation) {
-    case NoRoleOperation:
-        if ((event->pos() - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) {
-            // A role gets dragged by the user. Create a pixmap of the role that will get
-            // synchronized on each furter mouse-move-event with the mouse-position.
-            m_roleOperation = MoveRoleOperation;
-            const int roleIndex = roleIndexAt(m_pressedMousePos);
-            m_movingRole.index = roleIndex;
-            if (roleIndex == 0) {
-                // TODO: It should be configurable whether moving the first role is allowed.
-                // In the context of Dolphin this is not required, however this should be
-                // changed if KItemViews are used in a more generic way.
-                QApplication::setOverrideCursor(QCursor(Qt::ForbiddenCursor));
-            } else {
-                m_movingRole.pixmap = createRolePixmap(roleIndex);
-
-                qreal roleX = 0;
-                for (int i = 0; i < roleIndex; ++i) {
-                    const QByteArray role = m_visibleRoles[i];
-                    roleX += m_visibleRolesWidths.value(role);
-                }
-
-                m_movingRole.xDec = event->pos().x() - roleX;
-                m_movingRole.x = roleX;
-                update();
-            }
+    if (m_headerWidget->automaticColumnResizing() != automatic) {
+        m_headerWidget->setAutomaticColumnResizing(automatic);
+        if (automatic) {
+            m_view->updateColumnWidthsForHeader();
         }
-        break;
-
-    case ResizeRoleOperation: {
-        const QByteArray pressedRole = m_visibleRoles[m_pressedRoleIndex];
-
-        qreal previousWidth = m_visibleRolesWidths.value(pressedRole);
-        qreal currentWidth = previousWidth;
-        currentWidth += event->pos().x() - event->lastPos().x();
-        currentWidth = qMax(minimumRoleWidth(), currentWidth);
-
-        m_visibleRolesWidths.insert(pressedRole, currentWidth);
-        update();
-
-        emit visibleRoleWidthChanged(pressedRole, currentWidth, previousWidth);
-        break;
-    }
-
-    case MoveRoleOperation: {
-        // TODO: It should be configurable whether moving the first role is allowed.
-        // In the context of Dolphin this is not required, however this should be
-        // changed if KItemViews are used in a more generic way.
-        if (m_movingRole.index > 0) {
-            m_movingRole.x = event->pos().x() - m_movingRole.xDec;
-            update();
-
-            const int targetIndex = targetOfMovingRole();
-            if (targetIndex > 0 && targetIndex != m_movingRole.index) {
-                const QByteArray role = m_visibleRoles[m_movingRole.index];
-                const int previousIndex = m_movingRole.index;
-                m_movingRole.index = targetIndex;
-                emit visibleRoleMoved(role, targetIndex, previousIndex);
-
-                m_movingRole.xDec = event->pos().x() - roleXPosition(role);
-            }
-        }
-        break;
-    }
-
-    default:
-        break;
-    }
-}
-
-void KItemListHeader::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
-{
-    QGraphicsWidget::hoverEnterEvent(event);
-    updateHoveredRoleIndex(event->pos());
-}
-
-void KItemListHeader::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
-{
-    QGraphicsWidget::hoverLeaveEvent(event);
-    if (m_hoveredRoleIndex != -1) {
-        m_hoveredRoleIndex = -1;
-        update();
-    }
-}
-
-void KItemListHeader::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
-{
-    QGraphicsWidget::hoverMoveEvent(event);
-
-    const QPointF& pos = event->pos();
-    updateHoveredRoleIndex(pos);
-    if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) {
-        setCursor(Qt::SplitHCursor);
-    } else {
-        unsetCursor();
-    }
-}
-
-void KItemListHeader::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous)
-{
-    Q_UNUSED(current);
-    Q_UNUSED(previous);
-    update();
-}
-
-void KItemListHeader::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous)
-{
-    Q_UNUSED(current);
-    Q_UNUSED(previous);
-    update();
-}
-
-void KItemListHeader::paintRole(QPainter* painter,
-                                const QByteArray& role,
-                                const QRectF& rect,
-                                int orderIndex,
-                                QWidget* widget) const
-{
-    // The following code is based on the code from QHeaderView::paintSection().
-    // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-    QStyleOptionHeader option;
-    option.section = orderIndex;
-    option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal;
-    if (isEnabled()) {
-        option.state |= QStyle::State_Enabled;
-    }
-    if (window() && window()->isActiveWindow()) {
-        option.state |= QStyle::State_Active;
-    }
-    if (m_hoveredRoleIndex == orderIndex) {
-        option.state |= QStyle::State_MouseOver;
-    }
-    if (m_pressedRoleIndex == orderIndex) {
-        option.state |= QStyle::State_Sunken;
-    }
-    if (m_model->sortRole() == role) {
-        option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ?
-                                QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
-    }
-    option.rect = rect.toRect();
-
-    if (m_visibleRoles.count() == 1) {
-        option.position = QStyleOptionHeader::OnlyOneSection;
-    } else if (orderIndex == 0) {
-        option.position = QStyleOptionHeader::Beginning;
-    } else if (orderIndex == m_visibleRoles.count() - 1) {
-        option.position = QStyleOptionHeader::End;
-    } else {
-        option.position = QStyleOptionHeader::Middle;
-    }
-
-    option.orientation = Qt::Horizontal;
-    option.selectedPosition = QStyleOptionHeader::NotAdjacent;
-    option.text = m_model->roleDescription(role);
-
-    style()->drawControl(QStyle::CE_Header, &option, painter, widget);
-}
-
-void KItemListHeader::updatePressedRoleIndex(const QPointF& pos)
-{
-    const int pressedIndex = roleIndexAt(pos);
-    if (m_pressedRoleIndex != pressedIndex) {
-        m_pressedRoleIndex = pressedIndex;
-        update();
-    }
-}
-
-void KItemListHeader::updateHoveredRoleIndex(const QPointF& pos)
-{
-    const int hoverIndex = roleIndexAt(pos);
-    if (m_hoveredRoleIndex != hoverIndex) {
-        m_hoveredRoleIndex = hoverIndex;
-        update();
     }
 }
 
-int KItemListHeader::roleIndexAt(const QPointF& pos) const
+bool KItemListHeader::automaticColumnResizing() const
 {
-    int index = -1;
-
-    qreal x = 0;
-    foreach (const QByteArray& role, m_visibleRoles) {
-        ++index;
-        x += m_visibleRolesWidths.value(role);
-        if (pos.x() <= x) {
-            break;
-        }
-    }
-
-    return index;
+    return m_headerWidget->automaticColumnResizing();
 }
 
-bool KItemListHeader::isAboveRoleGrip(const QPointF& pos, int roleIndex) const
+void KItemListHeader::setColumnWidth(const QByteArray& role, qreal width)
 {
-    qreal x = 0;
-    for (int i = 0; i <= roleIndex; ++i) {
-        const QByteArray role = m_visibleRoles[i];
-        x += m_visibleRolesWidths.value(role);
+    if (!m_headerWidget->automaticColumnResizing()) {
+        m_headerWidget->setColumnWidth(role, width);
+        m_view->applyColumnWidthsFromHeader();
     }
-
-    const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
-    return pos.x() >= (x - grip) && pos.x() <= x;
 }
 
-QPixmap KItemListHeader::createRolePixmap(int roleIndex) const
+qreal KItemListHeader::columnWidth(const QByteArray& role) const
 {
-    const QByteArray role = m_visibleRoles[roleIndex];
-    const qreal roleWidth = m_visibleRolesWidths.value(role);
-    const QRect rect(0, 0, roleWidth, size().height());
-
-    QImage image(rect.size(), QImage::Format_ARGB32_Premultiplied);
-
-    QPainter painter(&image);
-    paintRole(&painter, role, rect, roleIndex);
-
-    // Apply a highlighting-color
-    const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive;
-    QColor highlightColor = palette().color(group, QPalette::Highlight);
-    highlightColor.setAlpha(64);
-    painter.fillRect(rect, highlightColor);
-
-    // Make the image transparent
-    painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
-    painter.fillRect(0, 0, image.width(), image.height(), QColor(0, 0, 0, 192));
-
-    return QPixmap::fromImage(image);
+    return m_headerWidget->columnWidth(role);
 }
 
-int KItemListHeader::targetOfMovingRole() const
+void KItemListHeader::setColumnWidths(const QHash<QByteArray, qreal>& columnWidths)
 {
-    const int movingWidth = m_movingRole.pixmap.width();
-    const int movingLeft = m_movingRole.x;
-    const int movingRight = movingLeft + movingWidth - 1;
-
-    int targetIndex = 0;
-    qreal targetLeft = 0;
-    while (targetIndex < m_visibleRoles.count()) {
-        const QByteArray role = m_visibleRoles[targetIndex];
-        const qreal targetWidth = m_visibleRolesWidths.value(role);
-        const qreal targetRight = targetLeft + targetWidth - 1;
-
-        const bool isInTarget = (targetWidth >= movingWidth &&
-                                 movingLeft  >= targetLeft  &&
-                                 movingRight <= targetRight) ||
-                                (targetWidth <  movingWidth &&
-                                 movingLeft  <= targetLeft  &&
-                                 movingRight >= targetRight);
-
-        if (isInTarget) {
-            return targetIndex;
+    if (!m_headerWidget->automaticColumnResizing()) {
+        foreach (const QByteArray& role, m_view->visibleRoles()) {
+            const qreal width = columnWidths.value(role);
+            m_headerWidget->setColumnWidth(role, width);
         }
 
-        targetLeft += targetWidth;
-        ++targetIndex;
+        m_view->applyColumnWidthsFromHeader();
     }
-
-    return m_movingRole.index;
 }
 
-qreal KItemListHeader::roleXPosition(const QByteArray& role) const
+KItemListHeader::KItemListHeader(KItemListView* listView) :
+    QObject(listView->parent()),
+    m_view(listView)
 {
-    qreal x = 0;
-    foreach (const QByteArray& visibleRole, m_visibleRoles) {
-        if (visibleRole == role) {
-            return x;
-        }
-
-        x += m_visibleRolesWidths.value(visibleRole);
-    }
+    m_headerWidget = m_view->m_headerWidget;
+    Q_ASSERT(m_headerWidget);
 
-    return -1;
+    connect(m_headerWidget, SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)),
+            this, SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)));
 }
 
-#include "kitemlistheader_p.moc"
+#include "kitemlistheader.moc"
diff --git a/src/kitemviews/kitemlistheader.h b/src/kitemviews/kitemlistheader.h
new file mode 100644 (file)
index 0000000..d0aae7f
--- /dev/null
@@ -0,0 +1,89 @@
+/***************************************************************************
+ *   Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com>             *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#ifndef KITEMLISTHEADER_H
+#define KITEMLISTHEADER_H
+
+#include <libdolphin_export.h>
+#include <QHash>
+#include <QObject>
+
+class KItemListHeaderWidget;
+class KItemListView;
+
+/**
+ * @brief Provides access to the header of a KItemListView.
+ *
+ * Each column of the header represents a visible role
+ * accessible by KItemListView::visibleRoles().
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListHeader : public QObject
+{
+    Q_OBJECT
+
+public:
+    virtual ~KItemListHeader();
+
+    /**
+     * If set to true, KItemListView will automatically adjust the
+     * widths of the columns. If set to false, the size can be
+     * manually adjusted by KItemListHeader::setColumnWidth().
+     */
+    void setAutomaticColumnResizing(bool automatic);
+    bool automaticColumnResizing() const;
+
+    /**
+     * Sets the width of the column for the given role. Note that
+     * the width only gets applied if KItemListHeader::automaticColumnResizing()
+     * has been turned off.
+     */
+    void setColumnWidth(const QByteArray& role, qreal width);
+    qreal columnWidth(const QByteArray& role) const;
+
+    /**
+     * Sets the widths of the columns for all roles. From a performance point of
+     * view calling this method should be preferred over several setColumnWidth()
+     * calls in case if the width of more than one column should be changed.
+     * Note that the widths only get applied if KItemListHeader::automaticColumnResizing()
+     * has been turned off.
+     */
+    void setColumnWidths(const QHash<QByteArray, qreal>& columnWidths);
+
+signals:
+    /**
+     * Is emitted if the width of a column has been adjusted by the user with the mouse
+     * (no signal is emitted if KItemListHeader::setColumnWidth() is invoked).
+     */
+    void columnWidthChanged(const QByteArray& role,
+                            qreal currentWidth,
+                            qreal previousWidth);
+
+private:
+    KItemListHeader(KItemListView* listView);
+
+private:
+    KItemListView* m_view;
+    KItemListHeaderWidget* m_headerWidget;
+
+    friend class KItemListView; // Constructs the KItemListHeader instance
+};
+
+#endif
+
+
diff --git a/src/kitemviews/kitemlistheaderwidget.cpp b/src/kitemviews/kitemlistheaderwidget.cpp
new file mode 100644 (file)
index 0000000..2f3058a
--- /dev/null
@@ -0,0 +1,507 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>             *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#include "kitemlistheaderwidget_p.h"
+
+#include <KAction>
+#include <KMenu>
+#include "kitemmodelbase.h"
+
+#include <QApplication>
+#include <QGraphicsSceneHoverEvent>
+#include <QPainter>
+#include <QStyleOptionHeader>
+
+#include <KDebug>
+
+KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget* parent) :
+    QGraphicsWidget(parent),
+    m_automaticColumnResizing(false),
+    m_model(0),
+    m_columns(),
+    m_columnsWidths(),
+    m_hoveredRoleIndex(-1),
+    m_pressedRoleIndex(-1),
+    m_roleOperation(NoRoleOperation),
+    m_pressedMousePos(),
+    m_movingRole()
+{
+    m_movingRole.x = 0;
+    m_movingRole.xDec = 0;
+    m_movingRole.index = -1;
+
+    setAcceptHoverEvents(true);
+
+    QStyleOptionHeader option;
+    const QSize headerSize = style()->sizeFromContents(QStyle::CT_HeaderSection, &option, QSize());
+    resize(0, headerSize.height());
+}
+
+KItemListHeaderWidget::~KItemListHeaderWidget()
+{
+}
+
+void KItemListHeaderWidget::setModel(KItemModelBase* model)
+{
+    if (m_model == model) {
+        return;
+    }
+
+    if (m_model) {
+        disconnect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
+                   this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
+        disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
+                   this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
+    }
+
+    m_model = model;
+
+    if (m_model) {
+        connect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)),
+                this, SLOT(slotSortRoleChanged(QByteArray,QByteArray)));
+        connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
+                this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder)));
+    }
+}
+
+KItemModelBase* KItemListHeaderWidget::model() const
+{
+    return m_model;
+}
+
+void KItemListHeaderWidget::setAutomaticColumnResizing(bool automatic)
+{
+    m_automaticColumnResizing = automatic;
+}
+
+bool KItemListHeaderWidget::automaticColumnResizing() const
+{
+    return m_automaticColumnResizing;
+}
+
+void KItemListHeaderWidget::setColumns(const QList<QByteArray>& roles)
+{
+    m_columns = roles;
+    update();
+}
+
+QList<QByteArray> KItemListHeaderWidget::columns() const
+{
+    return m_columns;
+}
+
+void KItemListHeaderWidget::setColumnWidth(const QByteArray& role, qreal width)
+{
+    const qreal minWidth = minimumColumnWidth();
+    if (width < minWidth) {
+        width = minWidth;
+    }
+
+    if (m_columnsWidths.value(role) != width) {
+        m_columnsWidths.insert(role, width);
+        update();
+    }
+}
+
+qreal KItemListHeaderWidget::columnWidth(const QByteArray& role) const
+{
+    return m_columnsWidths.value(role);
+}
+
+qreal KItemListHeaderWidget::minimumColumnWidth() const
+{
+    QFontMetricsF fontMetrics(font());
+    return fontMetrics.height() * 4;
+}
+
+void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+{
+    Q_UNUSED(option);
+    Q_UNUSED(widget);
+
+    if (!m_model) {
+        return;
+    }
+
+    // Draw roles
+    painter->setFont(font());
+    painter->setPen(palette().text().color());
+
+    qreal x = 0;
+    int orderIndex = 0;
+    foreach (const QByteArray& role, m_columns) {
+        const qreal roleWidth = m_columnsWidths.value(role);
+        const QRectF rect(x, 0, roleWidth, size().height());
+        paintRole(painter, role, rect, orderIndex, widget);
+        x += roleWidth;
+        ++orderIndex;
+    }
+
+    // Draw background without roles
+    QStyleOption opt;
+    opt.init(widget);
+    opt.rect = QRect(x, 0, size().width() - x, size().height());
+    opt.state |= QStyle::State_Horizontal;
+    style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, painter);
+
+    if (!m_movingRole.pixmap.isNull()) {
+        Q_ASSERT(m_roleOperation == MoveRoleOperation);
+        painter->drawPixmap(m_movingRole.x, 0, m_movingRole.pixmap);
+    }
+}
+
+void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent* event)
+{
+    if (event->button() & Qt::LeftButton) {
+        updatePressedRoleIndex(event->pos());
+        m_pressedMousePos = event->pos();
+        m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ?
+                          ResizeRoleOperation : NoRoleOperation;
+        event->accept();
+    } else {
+        event->ignore();
+    }
+}
+
+void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
+{
+    QGraphicsWidget::mouseReleaseEvent(event);
+
+    if (m_pressedRoleIndex == -1) {
+        return;
+    }
+
+    switch (m_roleOperation) {
+    case NoRoleOperation: {
+        // Only a click has been done and no moving or resizing has been started
+        const QByteArray sortRole = m_model->sortRole();
+        const int sortRoleIndex = m_columns.indexOf(sortRole);
+        if (m_pressedRoleIndex == sortRoleIndex) {
+            // Toggle the sort order
+            const Qt::SortOrder previous = m_model->sortOrder();
+            const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ?
+                                          Qt::DescendingOrder : Qt::AscendingOrder;
+            m_model->setSortOrder(current);
+            emit sortOrderChanged(current, previous);
+        } else {
+            // Change the sort role
+            const QByteArray previous = m_model->sortRole();
+            const QByteArray current = m_columns[m_pressedRoleIndex];
+            m_model->setSortRole(current);
+            emit sortRoleChanged(current, previous);
+        }
+        break;
+    }
+
+    case MoveRoleOperation:
+        m_movingRole.pixmap = QPixmap();
+        m_movingRole.x = 0;
+        m_movingRole.xDec = 0;
+        m_movingRole.index = -1;
+        break;
+
+    default:
+        break;
+    }
+
+    m_pressedRoleIndex = -1;
+    m_roleOperation = NoRoleOperation;
+    update();
+
+    QApplication::restoreOverrideCursor();
+}
+
+void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
+{
+    QGraphicsWidget::mouseMoveEvent(event);
+
+    switch (m_roleOperation) {
+    case NoRoleOperation:
+        if ((event->pos() - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) {
+            // A role gets dragged by the user. Create a pixmap of the role that will get
+            // synchronized on each furter mouse-move-event with the mouse-position.
+            m_roleOperation = MoveRoleOperation;
+            const int roleIndex = roleIndexAt(m_pressedMousePos);
+            m_movingRole.index = roleIndex;
+            if (roleIndex == 0) {
+                // TODO: It should be configurable whether moving the first role is allowed.
+                // In the context of Dolphin this is not required, however this should be
+                // changed if KItemViews are used in a more generic way.
+                QApplication::setOverrideCursor(QCursor(Qt::ForbiddenCursor));
+            } else {
+                m_movingRole.pixmap = createRolePixmap(roleIndex);
+
+                qreal roleX = 0;
+                for (int i = 0; i < roleIndex; ++i) {
+                    const QByteArray role = m_columns[i];
+                    roleX += m_columnsWidths.value(role);
+                }
+
+                m_movingRole.xDec = event->pos().x() - roleX;
+                m_movingRole.x = roleX;
+                update();
+            }
+        }
+        break;
+
+    case ResizeRoleOperation: {
+        const QByteArray pressedRole = m_columns[m_pressedRoleIndex];
+
+        qreal previousWidth = m_columnsWidths.value(pressedRole);
+        qreal currentWidth = previousWidth;
+        currentWidth += event->pos().x() - event->lastPos().x();
+        currentWidth = qMax(minimumColumnWidth(), currentWidth);
+
+        m_columnsWidths.insert(pressedRole, currentWidth);
+        update();
+
+        emit columnWidthChanged(pressedRole, currentWidth, previousWidth);
+        break;
+    }
+
+    case MoveRoleOperation: {
+        // TODO: It should be configurable whether moving the first role is allowed.
+        // In the context of Dolphin this is not required, however this should be
+        // changed if KItemViews are used in a more generic way.
+        if (m_movingRole.index > 0) {
+            m_movingRole.x = event->pos().x() - m_movingRole.xDec;
+            update();
+
+            const int targetIndex = targetOfMovingRole();
+            if (targetIndex > 0 && targetIndex != m_movingRole.index) {
+                const QByteArray role = m_columns[m_movingRole.index];
+                const int previousIndex = m_movingRole.index;
+                m_movingRole.index = targetIndex;
+                emit columnMoved(role, targetIndex, previousIndex);
+
+                m_movingRole.xDec = event->pos().x() - roleXPosition(role);
+            }
+        }
+        break;
+    }
+
+    default:
+        break;
+    }
+}
+
+void KItemListHeaderWidget::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
+{
+    QGraphicsWidget::hoverEnterEvent(event);
+    updateHoveredRoleIndex(event->pos());
+}
+
+void KItemListHeaderWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
+{
+    QGraphicsWidget::hoverLeaveEvent(event);
+    if (m_hoveredRoleIndex != -1) {
+        m_hoveredRoleIndex = -1;
+        update();
+    }
+}
+
+void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
+{
+    QGraphicsWidget::hoverMoveEvent(event);
+
+    const QPointF& pos = event->pos();
+    updateHoveredRoleIndex(pos);
+    if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) {
+        setCursor(Qt::SplitHCursor);
+    } else {
+        unsetCursor();
+    }
+}
+
+void KItemListHeaderWidget::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous)
+{
+    Q_UNUSED(current);
+    Q_UNUSED(previous);
+    update();
+}
+
+void KItemListHeaderWidget::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous)
+{
+    Q_UNUSED(current);
+    Q_UNUSED(previous);
+    update();
+}
+
+void KItemListHeaderWidget::paintRole(QPainter* painter,
+                                const QByteArray& role,
+                                const QRectF& rect,
+                                int orderIndex,
+                                QWidget* widget) const
+{
+    // The following code is based on the code from QHeaderView::paintSection().
+    // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+    QStyleOptionHeader option;
+    option.section = orderIndex;
+    option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal;
+    if (isEnabled()) {
+        option.state |= QStyle::State_Enabled;
+    }
+    if (window() && window()->isActiveWindow()) {
+        option.state |= QStyle::State_Active;
+    }
+    if (m_hoveredRoleIndex == orderIndex) {
+        option.state |= QStyle::State_MouseOver;
+    }
+    if (m_pressedRoleIndex == orderIndex) {
+        option.state |= QStyle::State_Sunken;
+    }
+    if (m_model->sortRole() == role) {
+        option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ?
+                                QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
+    }
+    option.rect = rect.toRect();
+
+    if (m_columns.count() == 1) {
+        option.position = QStyleOptionHeader::OnlyOneSection;
+    } else if (orderIndex == 0) {
+        option.position = QStyleOptionHeader::Beginning;
+    } else if (orderIndex == m_columns.count() - 1) {
+        option.position = QStyleOptionHeader::End;
+    } else {
+        option.position = QStyleOptionHeader::Middle;
+    }
+
+    option.orientation = Qt::Horizontal;
+    option.selectedPosition = QStyleOptionHeader::NotAdjacent;
+    option.text = m_model->roleDescription(role);
+
+    style()->drawControl(QStyle::CE_Header, &option, painter, widget);
+}
+
+void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF& pos)
+{
+    const int pressedIndex = roleIndexAt(pos);
+    if (m_pressedRoleIndex != pressedIndex) {
+        m_pressedRoleIndex = pressedIndex;
+        update();
+    }
+}
+
+void KItemListHeaderWidget::updateHoveredRoleIndex(const QPointF& pos)
+{
+    const int hoverIndex = roleIndexAt(pos);
+    if (m_hoveredRoleIndex != hoverIndex) {
+        m_hoveredRoleIndex = hoverIndex;
+        update();
+    }
+}
+
+int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const
+{
+    int index = -1;
+
+    qreal x = 0;
+    foreach (const QByteArray& role, m_columns) {
+        ++index;
+        x += m_columnsWidths.value(role);
+        if (pos.x() <= x) {
+            break;
+        }
+    }
+
+    return index;
+}
+
+bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) const
+{
+    qreal x = 0;
+    for (int i = 0; i <= roleIndex; ++i) {
+        const QByteArray role = m_columns[i];
+        x += m_columnsWidths.value(role);
+    }
+
+    const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
+    return pos.x() >= (x - grip) && pos.x() <= x;
+}
+
+QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const
+{
+    const QByteArray role = m_columns[roleIndex];
+    const qreal roleWidth = m_columnsWidths.value(role);
+    const QRect rect(0, 0, roleWidth, size().height());
+
+    QImage image(rect.size(), QImage::Format_ARGB32_Premultiplied);
+
+    QPainter painter(&image);
+    paintRole(&painter, role, rect, roleIndex);
+
+    // Apply a highlighting-color
+    const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive;
+    QColor highlightColor = palette().color(group, QPalette::Highlight);
+    highlightColor.setAlpha(64);
+    painter.fillRect(rect, highlightColor);
+
+    // Make the image transparent
+    painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+    painter.fillRect(0, 0, image.width(), image.height(), QColor(0, 0, 0, 192));
+
+    return QPixmap::fromImage(image);
+}
+
+int KItemListHeaderWidget::targetOfMovingRole() const
+{
+    const int movingWidth = m_movingRole.pixmap.width();
+    const int movingLeft = m_movingRole.x;
+    const int movingRight = movingLeft + movingWidth - 1;
+
+    int targetIndex = 0;
+    qreal targetLeft = 0;
+    while (targetIndex < m_columns.count()) {
+        const QByteArray role = m_columns[targetIndex];
+        const qreal targetWidth = m_columnsWidths.value(role);
+        const qreal targetRight = targetLeft + targetWidth - 1;
+
+        const bool isInTarget = (targetWidth >= movingWidth &&
+                                 movingLeft  >= targetLeft  &&
+                                 movingRight <= targetRight) ||
+                                (targetWidth <  movingWidth &&
+                                 movingLeft  <= targetLeft  &&
+                                 movingRight >= targetRight);
+
+        if (isInTarget) {
+            return targetIndex;
+        }
+
+        targetLeft += targetWidth;
+        ++targetIndex;
+    }
+
+    return m_movingRole.index;
+}
+
+qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const
+{
+    qreal x = 0;
+    foreach (const QByteArray& visibleRole, m_columns) {
+        if (visibleRole == role) {
+            return x;
+        }
+
+        x += m_columnsWidths.value(visibleRole);
+    }
+
+    return -1;
+}
+
+#include "kitemlistheaderwidget_p.moc"
similarity index 78%
rename from src/kitemviews/kitemlistheader_p.h
rename to src/kitemviews/kitemlistheaderwidget_p.h
index a0e54f5e315f0f78b93b3cb12348a83009a533a5..ea8bb1ef9c43eb685966658e229d437d41abf63e 100644 (file)
@@ -17,8 +17,8 @@
  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
  ***************************************************************************/
 
-#ifndef KITEMLISTHEADER_H
-#define KITEMLISTHEADER_H
+#ifndef KITEMLISTHEADERWIDGET_H
+#define KITEMLISTHEADERWIDGET_H
 
 #include <libdolphin_export.h>
 #include <QGraphicsWidget>
 class KItemModelBase;
 
 /**
- * @brief Header for KItemListView that shows the currently used roles.
+ * @brief Widget the implements the header for KItemListView showing the currently used roles.
+ *
+ * The widget is an internal API, the user of KItemListView may only access the
+ * class KItemListHeader.
  */
-class LIBDOLPHINPRIVATE_EXPORT KItemListHeader : public QGraphicsWidget
+class LIBDOLPHINPRIVATE_EXPORT KItemListHeaderWidget : public QGraphicsWidget
 {
     Q_OBJECT
 
 public:
-    KItemListHeader(QGraphicsWidget* parent = 0);
-    virtual ~KItemListHeader();
+    KItemListHeaderWidget(QGraphicsWidget* parent = 0);
+    virtual ~KItemListHeaderWidget();
 
     void setModel(KItemModelBase* model);
     KItemModelBase* model() const;
 
-    void setVisibleRoles(const QList<QByteArray>& roles);
-    QList<QByteArray> visibleRoles() const;
+    void setAutomaticColumnResizing(bool automatic);
+    bool automaticColumnResizing() const;
 
-    void setVisibleRolesWidths(const QHash<QByteArray, qreal>& rolesWidths);
-    QHash<QByteArray, qreal> visibleRolesWidths() const;
+    void setColumns(const QList<QByteArray>& roles);
+    QList<QByteArray> columns() const;
 
-    qreal minimumRoleWidth() const;
+    void setColumnWidth(const QByteArray& role, qreal width);
+    qreal columnWidth(const QByteArray& role) const;
+
+    qreal minimumColumnWidth() const;
 
     virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
 
 signals:
     /**
      * Is emitted if the width of a visible role has been adjusted by the user with the mouse
-     * (no signal is emitted if KItemListHeader::setVisibleRoles() is invoked).
+     * (no signal is emitted if KItemListHeader::setVisibleRoleWidth() is invoked).
      */
-    void visibleRoleWidthChanged(const QByteArray& role,
-                                 qreal currentWidth,
-                                 qreal previousWidth);
+    void columnWidthChanged(const QByteArray& role,
+                            qreal currentWidth,
+                            qreal previousWidth);
 
     /**
-     * Is emitted if the position of the visible role has been changed.
+     * Is emitted if the position of the column has been changed.
      */
-    void visibleRoleMoved(const QByteArray& role, int currentIndex, int previousIndex);
+    void columnMoved(const QByteArray& role, int currentIndex, int previousIndex);
 
     /**
      * Is emitted if the user has changed the sort order by clicking on a
@@ -130,9 +136,10 @@ private:
         MoveRoleOperation
     };
 
+    bool m_automaticColumnResizing;
     KItemModelBase* m_model;
-    QList<QByteArray> m_visibleRoles;
-    QHash<QByteArray, qreal> m_visibleRolesWidths;
+    QList<QByteArray> m_columns;
+    QHash<QByteArray, qreal> m_columnsWidths;
 
     int m_hoveredRoleIndex;
     int m_pressedRoleIndex;
index 0880687e12b7cda0b9c10f3c22dc9dd453f99015..ff1cbc39ae12a92bba3964dfcfcf054c7c3b6f3e 100644 (file)
@@ -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<QByteArray>& 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<QByteArray>& 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<QByteArray, QSizeF> KItemListView::visibleRolesSizes(const KItemRangeList& itemRanges) const
+QHash<QByteArray, qreal> KItemListView::columnWidths(const KItemRangeList& itemRanges) const
 {
     Q_UNUSED(itemRanges);
-    return QHash<QByteArray, QSizeF>();
+    return QHash<QByteArray, qreal>();
 }
 
 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<int>& indexes) const
@@ -803,7 +819,7 @@ QList<KItemListWidget*> 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<int, KItemListWidget*> 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<QByteArray, qreal> KItemListView::headerRolesWidths() const
+void KItemListView::applyColumnWidthsFromHeader()
 {
-    QHash<QByteArray, qreal> 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<QByteArray, QSizeF> it(m_stretchedVisibleRolesSizes);
+    // Update the role sizes for all visible widgets
+    QHashIterator<int, KItemListWidget*> 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<QByteArray, QSizeF> it (m_visibleRolesSizes);
+            const qreal minHeaderRoleWidth = m_headerWidget->minimumColumnWidth();
+            QMutableHashIterator<QByteArray, qreal> 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<QByteArray, QSizeF> updatedSizes = visibleRolesSizes(itemRanges);
-        QHashIterator<QByteArray, QSizeF> it(updatedSizes);
+        const QHash<QByteArray, qreal> updatedWidths = columnWidths(itemRanges);
+        QHashIterator<QByteArray, qreal> 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<int, KItemListWidget*> 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<QByteArray, QSizeF> it(m_visibleRolesSizes);
+    QHashIterator<QByteArray, qreal> 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<QByteArray, QSizeF> 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,
index bbdb4081ca574d8bfc42b0561f63e2c964c5060b..70ba03061a6e49357dfb0d4deffcf8177fcddac6 100644 (file)
@@ -36,6 +36,7 @@
 class KItemListController;
 class KItemListGroupHeaderCreatorBase;
 class KItemListHeader;
+class KItemListHeaderWidget;
 class KItemListSizeHintResolver;
 class KItemListRubberBand;
 class KItemListViewAnimation;
@@ -192,13 +193,13 @@ public:
     virtual QSizeF itemSizeHint(int index) const;
 
     /**
-     * @param itemRanges Items that must be checked for getting the visible roles sizes.
-     * @return           The size of each visible role in case if KItemListView::itemSize()
-     *                   is empty. This allows to have dynamic but equal role sizes between
-     *                   all items, like used in the classic "table-views". Per default an
-     *                   empty hash is returned.
+     * @param itemRanges Items that must be checked for getting the widths of columns.
+     * @return           The width of the column of each visible role. The width will
+     *                   be respected if the width of the item size is <= 0 (see
+     *                   KItemListView::setItemSize()). Per default an empty hash
+     *                   is returned.
      */
-    virtual QHash<QByteArray, QSizeF> visibleRolesSizes(const KItemRangeList& itemRanges) const;
+    virtual QHash<QByteArray, qreal> columnWidths(const KItemRangeList& itemRanges) const;
 
     /**
      * If set to true, items having child-items can be expanded to show the child-items as
@@ -253,12 +254,18 @@ public:
     bool isTransactionActive() const;
 
     /**
-     * Turns on the header if \p show is true. Per default the
-     * header is not shown. Usually the header is turned on when
+     * Turns on the header if \p visible is true. Per default the
+     * header is not visible. Usually the header is turned on when
      * showing a classic "table-view" to describe the shown columns.
      */
-    void setHeaderShown(bool show);
-    bool isHeaderShown() const;
+    void setHeaderVisible(bool visible);
+    bool isHeaderVisible() const;
+
+    /**
+     * @return Header of the list. The header is also available if it is not shown
+     *         (see KItemListView::setHeaderShown()).
+     */
+    KItemListHeader* header() const;
 
     /**
      * @return Pixmap that is used for a drag operation based on the
@@ -364,22 +371,22 @@ private slots:
     void slotRubberBandActivationChanged(bool active);
 
     /**
-     * Is invoked if the visible role-width of one role in the header has
+     * Is invoked if the column-width of one role in the header has
      * been changed by the user. It is remembered that the user has modified
      * the role-width, so that it won't be changed anymore automatically to
      * calculate an optimized width.
      */
-    void slotVisibleRoleWidthChanged(const QByteArray& role,
-                                     qreal currentWidth,
-                                     qreal previousWidth);
+    void slotHeaderColumnWidthChanged(const QByteArray& role,
+                                      qreal currentWidth,
+                                      qreal previousWidth);
 
     /**
-     * Is invoked if a visible role has been moved by the user. Applies
+     * Is invoked if a column has been moved by the user. Applies
      * the moved role to the view.
      */
-    void slotVisibleRoleMoved(const QByteArray& role,
-                              int currentIndex,
-                              int previousIndex);
+    void slotHeaderColumnMoved(const QByteArray& role,
+                               int currentIndex,
+                               int previousIndex);
 
     /**
      * Triggers the autoscrolling if autoScroll() is enabled by checking the
@@ -517,10 +524,13 @@ private:
      */
     bool useAlternateBackgrounds() const;
 
+    void applyColumnWidthsFromHeader();
+
     /**
-     * @return The widths of each visible role that is shown in the KItemListHeader.
+     * Applies the roles-sizes from m_stretchedVisibleRolesSizes
+     * to \a widget.
      */
-    QHash<QByteArray, qreal> headerRolesWidths() const;
+    void updateWidgetColumnWidths(KItemListWidget* widget);
 
     /**
      * Updates m_visibleRolesSizes by calling KItemListView::visibleRolesSizes().
@@ -528,29 +538,23 @@ private:
      * are used (see m_useHeaderWidths). Also m_strechedVisibleRolesSizes will be adjusted
      * to respect the available view-size.
      */
-    void updateVisibleRolesSizes(const KItemRangeList& itemRanges);
+    void updateColumnWidthsCache(const KItemRangeList& itemRanges);
 
     /**
      * Convenience method for updateVisibleRoleSizes(KItemRangeList() << KItemRange(0, m_model->count()).
      */
-    void updateVisibleRolesSizes();
+    void updateColumnWidthsCache();
 
     /**
-     * Updates m_stretchedVisibleRolesSizes based on m_visibleRolesSizes and the available
-     * view-size. Nothing will be done if m_itemRect is not empty or custom header-widths
-     * are used (see m_useHeaderWidths).
+     * Updates the column widhts of the header based on m_columnWidthsCache and the available
+     * view-size.
      */
-    void updateStretchedVisibleRolesSizes();
+    void updateColumnWidthsForHeader();
 
     /**
-     * @return Sum of the widths of all visible roles.
+     * @return Sum of the widths of all columns.
      */
-    qreal visibleRolesSizesWidthSum() const;
-
-    /**
-     * @return Sum of the heights of all visible roles.
-     */
-    qreal visibleRolesSizesHeightSum() const;
+    qreal columnWidthsSum() const;
 
     /**
      * @return Boundaries of the header. An empty rectangle is returned
@@ -634,8 +638,6 @@ private:
     KItemListController* m_controller;
     KItemModelBase* m_model;
     QList<QByteArray> m_visibleRoles;
-    QHash<QByteArray, QSizeF> m_visibleRolesSizes;
-    QHash<QByteArray, QSizeF> m_stretchedVisibleRolesSizes;
     KItemListWidgetCreatorBase* m_widgetCreator;
     KItemListGroupHeaderCreatorBase* m_groupHeaderCreator;
     KItemListStyleOption m_styleOption;
@@ -643,6 +645,8 @@ private:
     QHash<int, KItemListWidget*> m_visibleItems;
     QHash<KItemListWidget*, KItemListGroupHeader*> m_visibleGroups;
 
+    QHash<QByteArray, qreal> m_columnWidthsCache; // Cache for columnWidths() result
+
     struct Cell
     {
         Cell() : column(-1), row(-1) {}
@@ -671,9 +675,10 @@ private:
     QTimer* m_autoScrollTimer;
 
     KItemListHeader* m_header;
-    bool m_useHeaderWidths;
+    KItemListHeaderWidget* m_headerWidget;
 
     friend class KItemListContainer; // Accesses scrollBarRequired()
+    friend class KItemListHeader;    // Accesses m_headerWidget
     friend class KItemListController;
     friend class KItemListControllerTest;
 };
index 951fb396c54faa540771d32bc1fc10fd981f16f6..b91e871672568e2ef74c18a15ac06df345a60235 100644 (file)
@@ -44,7 +44,7 @@ KItemListWidget::KItemListWidget(QGraphicsItem* parent) :
     m_enabledSelectionToggle(false),
     m_data(),
     m_visibleRoles(),
-    m_visibleRolesSizes(),
+    m_columnWidths(),
     m_styleOption(),
     m_siblingsInfo(),
     m_hoverOpacity(0),
@@ -177,18 +177,20 @@ QList<QByteArray> KItemListWidget::visibleRoles() const
     return m_visibleRoles;
 }
 
-void KItemListWidget::setVisibleRolesSizes(const QHash<QByteArray, QSizeF> rolesSizes)
-{
-    const QHash<QByteArray, QSizeF> previousRolesSizes = m_visibleRolesSizes;
-    m_visibleRolesSizes = rolesSizes;
 
-    visibleRolesSizesChanged(rolesSizes, previousRolesSizes);
-    update();
+void KItemListWidget::setColumnWidth(const QByteArray& role, qreal width)
+{
+    if (m_columnWidths.value(role) != width) {
+        const qreal previousWidth = width;
+        m_columnWidths.insert(role, width);
+        columnWidthChanged(role, width, previousWidth);
+        update();
+    }
 }
 
-QHash<QByteArray, QSizeF> KItemListWidget::visibleRolesSizes() const
+qreal KItemListWidget::columnWidth(const QByteArray& role) const
 {
-    return m_visibleRolesSizes;
+    return m_columnWidths.value(role);
 }
 
 void KItemListWidget::setStyleOption(const KItemListStyleOption& option)
@@ -352,9 +354,11 @@ void KItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
     Q_UNUSED(previous);
 }
 
-void KItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current,
-                                               const QHash<QByteArray, QSizeF>& previous)
+void KItemListWidget::columnWidthChanged(const QByteArray& role,
+                                         qreal current,
+                                         qreal previous)
 {
+    Q_UNUSED(role);
     Q_UNUSED(current);
     Q_UNUSED(previous);
 }
index 80f944748b114c967ba217d844466d75e680bbc4..66d96d44913390681a9fa87d7f93969ad8e11755 100644 (file)
@@ -65,8 +65,12 @@ public:
     void setVisibleRoles(const QList<QByteArray>& roles);
     QList<QByteArray> visibleRoles() const;
 
-    void setVisibleRolesSizes(const QHash<QByteArray, QSizeF> rolesSizes);
-    QHash<QByteArray, QSizeF> visibleRolesSizes() const;
+    /**
+     * Sets the width of a role that should be used if the alignment of the content
+     * should be done in columns.
+     */
+    void setColumnWidth(const QByteArray& role, qreal width);
+    qreal columnWidth(const QByteArray& role) const;
 
     void setStyleOption(const KItemListStyleOption& option);
     const KItemListStyleOption& styleOption() const;
@@ -133,7 +137,7 @@ public:
 protected:
     virtual void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>());
     virtual void visibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous);
-    virtual void visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current, const QHash<QByteArray, QSizeF>& previous);
+    virtual void columnWidthChanged(const QByteArray& role, qreal current, qreal previous);
     virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
     virtual void currentChanged(bool current);
     virtual void selectedChanged(bool selected);
@@ -168,7 +172,7 @@ private:
     bool m_enabledSelectionToggle;
     QHash<QByteArray, QVariant> m_data;
     QList<QByteArray> m_visibleRoles;
-    QHash<QByteArray, QSizeF> m_visibleRolesSizes;
+    QHash<QByteArray, qreal> m_columnWidths;
     KItemListStyleOption m_styleOption;
     QBitArray m_siblingsInfo;
 
index 3f2c46a9c19db924c936008ce5bba12981ba99d9..fced36b52099c1a46aed22d168ff26c4ec690c9e 100644 (file)
             <default></default>
         </entry>
 
+        <entry name="HeaderColumnWidths" type="IntList">
+            <label context="@label">Header column widths</label>
+            <default></default>
+        </entry>
+
         <entry name="Timestamp" type="DateTime" >
             <label context="@label">Properties last changed</label>
             <whatsthis context="@info:whatsthis">The last time these properties were changed by the user.</whatsthis>
index 1ece52093b1505a2444db8ea27ab0a4e5d4b4488..8224399487c4715e1e0a5042b78965ae59b2aaf1 100644 (file)
@@ -133,17 +133,17 @@ void DolphinItemListContainer::setItemLayout(KFileItemListView::Layout layout)
     switch (layout) {
     case KFileItemListView::IconsLayout:
         m_fileItemListView->setScrollOrientation(Qt::Vertical);
-        m_fileItemListView->setHeaderShown(false);
+        m_fileItemListView->setHeaderVisible(false);
         m_fileItemListView->setSupportsItemExpanding(false);
         break;
     case KFileItemListView::DetailsLayout:
         m_fileItemListView->setScrollOrientation(Qt::Vertical);
-        m_fileItemListView->setHeaderShown(true);
+        m_fileItemListView->setHeaderVisible(true);
         m_fileItemListView->setSupportsItemExpanding(DetailsModeSettings::expandableFolders());
         break;
     case KFileItemListView::CompactLayout:
         m_fileItemListView->setScrollOrientation(Qt::Horizontal);
-        m_fileItemListView->setHeaderShown(false);
+        m_fileItemListView->setHeaderVisible(false);
         m_fileItemListView->setSupportsItemExpanding(false);
         break;
     default:
index f3d386b3b7f24f3602dd29bb15f969200234e925..241f24fd41da236bb8b9a6c054be9587b4feec2f 100644 (file)
@@ -41,6 +41,7 @@
 #include <KLocale>
 #include <kitemviews/kfileitemmodel.h>
 #include <kitemviews/kfileitemlistview.h>
+#include <kitemviews/kitemlistheader.h>
 #include <kitemviews/kitemlistselectionmanager.h>
 #include <kitemviews/kitemlistview.h>
 #include <kitemviews/kitemlistcontroller.h>
@@ -161,6 +162,8 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) :
             this, SLOT(slotSortRoleChangedByHeader(QByteArray,QByteArray)));
     connect(view, SIGNAL(visibleRolesChanged(QList<QByteArray>,QList<QByteArray>)),
             this, SLOT(slotVisibleRolesChangedByHeader(QList<QByteArray>,QList<QByteArray>)));
+    connect(view->header(), SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)),
+            this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal)));
 
     KItemListSelectionManager* selectionManager = controller->selectionManager();
     connect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)),
@@ -774,7 +777,9 @@ void DolphinView::slotViewContextMenuRequested(const QPointF& pos)
 
 void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos)
 {
-    QWeakPointer<KMenu> menu = new KMenu(QApplication::activeWindow());
+    ViewProperties props(url());
+
+    QPointer<KMenu> menu = new KMenu(QApplication::activeWindow());
 
     KItemListView* view = m_container->controller()->view();
     const QSet<QByteArray> visibleRolesSet = view->visibleRoles().toSet();
@@ -793,11 +798,11 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos)
         const QString text = fileItemModel()->roleDescription(info.role);
         QAction* action = 0;
         if (info.group.isEmpty()) {
-            action = menu.data()->addAction(text);
+            action = menu->addAction(text);
         } else {
             if (!groupMenu || info.group != groupName) {
                 groupName = info.group;
-                groupMenu = menu.data()->addMenu(groupName);
+                groupMenu = menu->addMenu(groupName);
             }
 
             action = groupMenu->addAction(text);
@@ -808,24 +813,84 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos)
         action->setData(info.role);
     }
 
-    QAction* action = menu.data()->exec(pos.toPoint());
-    if (action) {
-        // Show or hide the selected role
-        const QByteArray selectedRole = action->data().toByteArray();
+    menu->addSeparator();
+
+    QActionGroup* widthsGroup = new QActionGroup(menu);
+    const bool autoColumnWidths = props.headerColumnWidths().isEmpty();
+
+    QAction* autoAdjustWidthsAction = menu->addAction(i18nc("@action:inmenu", "Automatic Column Widths"));
+    autoAdjustWidthsAction->setCheckable(true);
+    autoAdjustWidthsAction->setChecked(autoColumnWidths);
+    autoAdjustWidthsAction->setActionGroup(widthsGroup);
+
+    QAction* customWidthsAction = menu->addAction(i18nc("@action:inmenu", "Custom Column Widths"));
+    customWidthsAction->setCheckable(true);
+    customWidthsAction->setChecked(!autoColumnWidths);
+    customWidthsAction->setActionGroup(widthsGroup);
+
+    QAction* action = menu->exec(pos.toPoint());
+    if (menu && action) {
+        if (action == autoAdjustWidthsAction) {
+            // Clear the column-widths from the viewproperties and turn on
+            // the automatic resizing of the columns
+            props.setHeaderColumnWidths(QList<int>());
+            KItemListHeader* header = m_container->controller()->view()->header();
+            header->setAutomaticColumnResizing(true);
+        } else if (action == customWidthsAction) {
+            // Apply the current column-widths as custom column-widths and turn
+            // off the automatic resizing of the columns
+            const KItemListView* view = m_container->controller()->view();
+            KItemListHeader* header = view->header();
+
+            QList<int> columnWidths;
+            foreach (const QByteArray& role, view->visibleRoles()) {
+                columnWidths.append(header->columnWidth(role));
+            }
 
-        ViewProperties props(url());
-        QList<QByteArray> visibleRoles = view->visibleRoles();
-        if (action->isChecked()) {
-            visibleRoles.append(selectedRole);
+            props.setHeaderColumnWidths(columnWidths);
+            header->setAutomaticColumnResizing(false);
         } else {
-            visibleRoles.removeOne(selectedRole);
+            // Show or hide the selected role
+            const QByteArray selectedRole = action->data().toByteArray();
+
+            QList<QByteArray> visibleRoles = view->visibleRoles();
+            if (action->isChecked()) {
+                visibleRoles.append(selectedRole);
+            } else {
+                visibleRoles.removeOne(selectedRole);
+            }
+
+            view->setVisibleRoles(visibleRoles);
+            props.setVisibleRoles(visibleRoles);
         }
+    }
 
-        view->setVisibleRoles(visibleRoles);
-        props.setVisibleRoles(visibleRoles);
+    delete menu;
+}
+
+void DolphinView::slotHeaderColumnWidthChanged(const QByteArray& role, qreal current, qreal previous)
+{
+    Q_UNUSED(previous);
+
+    const QList<QByteArray> visibleRoles = m_container->visibleRoles();
+
+    ViewProperties props(url());
+    QList<int> columnWidths = props.headerColumnWidths();
+    if (columnWidths.count() != visibleRoles.count()) {
+        columnWidths.clear();
+        columnWidths.reserve(visibleRoles.count());
+        const KItemListHeader* header = m_container->controller()->view()->header();
+        foreach (const QByteArray& role, visibleRoles) {
+            const int width = header->columnWidth(role);
+            columnWidths.append(width);
+        }
     }
 
-    delete menu.data();
+    const int roleIndex = visibleRoles.indexOf(role);
+    Q_ASSERT(roleIndex >= 0 && roleIndex < columnWidths.count());
+    columnWidths[roleIndex] = current;
+
+    props.setHeaderColumnWidths(columnWidths);
 }
 
 void DolphinView::slotItemHovered(int index)
@@ -1294,6 +1359,24 @@ void DolphinView::applyViewProperties()
         }
     }
 
+    KItemListView* itemListView = m_container->controller()->view();
+    if (itemListView->isHeaderVisible()) {
+        KItemListHeader* header = itemListView->header();
+        const QList<int> headerColumnWidths = props.headerColumnWidths();
+        const int rolesCount = m_visibleRoles.count();
+        if (headerColumnWidths.count() == rolesCount) {
+            header->setAutomaticColumnResizing(false);
+
+            QHash<QByteArray, qreal> columnWidths;
+            for (int i = 0; i < rolesCount; ++i) {
+                columnWidths.insert(m_visibleRoles[i], headerColumnWidths[i]);
+            }
+            header->setColumnWidths(columnWidths);
+        } else {
+            header->setAutomaticColumnResizing(true);
+        }
+    }
+
     m_container->endTransaction();
 }
 
index 48d0646c46e96a1f06a8084a4d47a676e53e2850..71128569af8bda1c4952752d189bba4775235a43 100644 (file)
@@ -543,6 +543,7 @@ private slots:
     void slotItemContextMenuRequested(int index, const QPointF& pos);
     void slotViewContextMenuRequested(const QPointF& pos);
     void slotHeaderContextMenuRequested(const QPointF& pos);
+    void slotHeaderColumnWidthChanged(const QByteArray& role, qreal current, qreal previous);
     void slotItemHovered(int index);
     void slotItemUnhovered(int index);
     void slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event);
index 8588bb238c80f11f54d76b1daa5ef6fa6f392521..83958ad001550dfd955933760dad5cbb2303b40a 100644 (file)
@@ -292,6 +292,19 @@ QList<QByteArray> ViewProperties::visibleRoles() const
     return roles;
 }
 
+void ViewProperties::setHeaderColumnWidths(const QList<int>& widths)
+{
+    if (m_node->headerColumnWidths() != widths) {
+        m_node->setHeaderColumnWidths(widths);
+        update();
+    }
+}
+
+QList<int> ViewProperties::headerColumnWidths() const
+{
+    return m_node->headerColumnWidths();
+}
+
 void ViewProperties::setDirProperties(const ViewProperties& props)
 {
     setViewMode(props.viewMode());
@@ -302,6 +315,7 @@ void ViewProperties::setDirProperties(const ViewProperties& props)
     setSortOrder(props.sortOrder());
     setSortFoldersFirst(props.sortFoldersFirst());
     setVisibleRoles(props.visibleRoles());
+    setHeaderColumnWidths(props.headerColumnWidths());
 }
 
 void ViewProperties::setAutoSaveEnabled(bool autoSave)
index 96a5515ef19e49a988c07fbfef835a8db66c5c81..303c042271c879f5f166fb5627458318170dbb29 100644 (file)
@@ -88,6 +88,9 @@ public:
      */
     QList<QByteArray> visibleRoles() const;
 
+    void setHeaderColumnWidths(const QList<int>& widths);
+    QList<int> headerColumnWidths() const;
+
     /**
      * Sets the directory properties view mode, show preview,
      * show hidden files, sorting and sort order like