summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Penz <peter.penz19@gmail.com>2012-02-14 17:04:47 (GMT)
committerPeter Penz <peter.penz19@gmail.com>2012-02-14 17:04:47 (GMT)
commite505c3ae5a8df306992777b7ba121036a7d8933d (patch)
tree6a968750da4f72e5e33fec2484e5c4609943db7f
parent307cca7b31b998fb7e8af0478a8e97e53bdc059c (diff)
Details view: Fix indicator-branches
Up to now no indicator-branches have been drawn when showing a tree. The patch fixes this so that that the style-dependent branches are drawn. The main part of the patch is the implementation of KItemListView::updateSiblingsInformation(). Most of the other changes are related due to an internal renaming of the expansionsLevel-role to expandedParentsCount and some related cleanups. BUG: 290276 FIXED-IN: 4.8.1
-rw-r--r--dolphin/src/kitemviews/kfileitemlistview.cpp6
-rw-r--r--dolphin/src/kitemviews/kfileitemlistwidget.cpp77
-rw-r--r--dolphin/src/kitemviews/kfileitemlistwidget.h2
-rw-r--r--dolphin/src/kitemviews/kfileitemmodel.cpp144
-rw-r--r--dolphin/src/kitemviews/kfileitemmodel.h25
-rw-r--r--dolphin/src/kitemviews/kitemlistview.cpp128
-rw-r--r--dolphin/src/kitemviews/kitemlistview.h14
-rw-r--r--dolphin/src/kitemviews/kitemlistwidget.cpp33
-rw-r--r--dolphin/src/kitemviews/kitemlistwidget.h13
-rw-r--r--dolphin/src/kitemviews/kitemmodelbase.cpp6
-rw-r--r--dolphin/src/kitemviews/kitemmodelbase.h6
-rw-r--r--dolphin/src/tests/kfileitemmodeltest.cpp6
12 files changed, 347 insertions, 113 deletions
diff --git a/dolphin/src/kitemviews/kfileitemlistview.cpp b/dolphin/src/kitemviews/kfileitemlistview.cpp
index f8a58ae..03f3798 100644
--- a/dolphin/src/kitemviews/kfileitemlistview.cpp
+++ b/dolphin/src/kitemviews/kfileitemlistview.cpp
@@ -515,8 +515,8 @@ QSizeF KFileItemListView::visibleRoleSizeHint(int index, const QByteArray& role)
if (role == "name") {
// Increase the width by the expansion-toggle and the current expansion level
- const int expansionLevel = values.value("expansionLevel", 0).toInt();
- width += option.padding + expansionLevel * itemSize().height() + KIconLoader::SizeSmall;
+ const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
+ width += option.padding + expandedParentsCount * itemSize().height() + KIconLoader::SizeSmall;
// Increase the width by the required space for the icon
width += option.padding * 2 + option.iconSize;
@@ -582,7 +582,7 @@ void KFileItemListView::applyRolesToModel()
if (m_itemLayout == DetailsLayout) {
roles.insert("isExpanded");
roles.insert("isExpandable");
- roles.insert("expansionLevel");
+ roles.insert("expandedParentsCount");
}
// Assure that the role that is used for sorting will be determined
diff --git a/dolphin/src/kitemviews/kfileitemlistwidget.cpp b/dolphin/src/kitemviews/kfileitemlistwidget.cpp
index 64cc8b4..dc1554d 100644
--- a/dolphin/src/kitemviews/kfileitemlistwidget.cpp
+++ b/dolphin/src/kitemviews/kfileitemlistwidget.cpp
@@ -94,13 +94,8 @@ void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsIte
KItemListWidget::paint(painter, option, widget);
- // Draw expansion toggle '>' or 'V'
- if (m_isExpandable && !m_expansionArea.isEmpty()) {
- QStyleOption arrowOption;
- arrowOption.rect = m_expansionArea.toRect();
- const QStyle::PrimitiveElement arrow = data()["isExpanded"].toBool()
- ? QStyle::PE_IndicatorArrowDown : QStyle::PE_IndicatorArrowRight;
- style()->drawPrimitive(arrow, &arrowOption, painter);
+ if (!m_expansionArea.isEmpty()) {
+ drawSiblingsInformation(painter);
}
const KItemListStyleOption& itemListStyleOption = styleOption();
@@ -309,7 +304,8 @@ QPixmap KFileItemListWidget::overlay() const
void KFileItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
const QSet<QByteArray>& roles)
{
- KItemListWidget::dataChanged(current, roles);
+ Q_UNUSED(current);
+
m_dirtyContent = true;
QSet<QByteArray> dirtyRoles;
@@ -331,7 +327,7 @@ void KFileItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current
void KFileItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
const QList<QByteArray>& previous)
{
- KItemListWidget::visibleRolesChanged(current, previous);
+ Q_UNUSED(previous);
m_sortedVisibleRoles = current;
m_dirtyLayout = true;
}
@@ -339,14 +335,16 @@ void KFileItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
void KFileItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current,
const QHash<QByteArray, QSizeF>& previous)
{
- KItemListWidget::visibleRolesSizesChanged(current, previous);
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
m_dirtyLayout = true;
}
void KFileItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
const KItemListStyleOption& previous)
{
- KItemListWidget::styleOptionChanged(current, previous);
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
updateAdditionalInfoTextColor();
m_dirtyLayout = true;
}
@@ -363,6 +361,14 @@ void KFileItemListWidget::selectedChanged(bool selected)
updateAdditionalInfoTextColor();
}
+void KFileItemListWidget::siblingsInformationChanged(const QBitArray& current, const QBitArray& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ m_dirtyLayout = true;
+}
+
+
void KFileItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
{
KItemListWidget::resizeEvent(event);
@@ -428,15 +434,14 @@ void KFileItemListWidget::updateExpansionArea()
{
if (m_layout == DetailsLayout) {
const QHash<QByteArray, QVariant> values = data();
- Q_ASSERT(values.contains("expansionLevel"));
- const KItemListStyleOption& option = styleOption();
- const int expansionLevel = values.value("expansionLevel", 0).toInt();
- if (expansionLevel >= 0) {
+ Q_ASSERT(values.contains("expandedParentsCount"));
+ const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
+ if (expandedParentsCount >= 0) {
const qreal widgetHeight = size().height();
- const qreal expansionLevelSize = KIconLoader::SizeSmall;
- const qreal x = option.padding + expansionLevel * widgetHeight;
- const qreal y = (widgetHeight - expansionLevelSize) / 2;
- m_expansionArea = QRectF(x, y, expansionLevelSize, expansionLevelSize);
+ const qreal inc = (widgetHeight - KIconLoader::SizeSmall) / 2;
+ const qreal x = expandedParentsCount * widgetHeight + inc;
+ const qreal y = inc;
+ m_expansionArea = QRectF(x, y, KIconLoader::SizeSmall, KIconLoader::SizeSmall);
return;
}
}
@@ -746,7 +751,8 @@ void KFileItemListWidget::updateDetailsLayoutTextCache()
const int fontHeight = option.fontMetrics.height();
const qreal columnPadding = option.padding * 3;
- const qreal firstColumnInc = m_expansionArea.right() + option.padding * 2 + scaledIconSize;
+ const qreal firstColumnInc = (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2
+ + scaledIconSize;
qreal x = firstColumnInc;
const qreal y = qMax(qreal(option.padding), (widgetHeight - fontHeight) / 2);
@@ -831,6 +837,37 @@ void KFileItemListWidget::drawPixmap(QPainter* painter, const QPixmap& pixmap)
}
}
+void KFileItemListWidget::drawSiblingsInformation(QPainter* painter)
+{
+ const int siblingSize = size().height();
+ const int x = (m_expansionArea.left() + m_expansionArea.right() - siblingSize) / 2;
+ QRect siblingRect(x, 0, siblingSize, siblingSize);
+
+ QStyleOption option;
+ bool isItemSibling = true;
+
+ const QBitArray siblings = siblingsInformation();
+ for (int i = siblings.count() - 1; i >= 0; --i) {
+ option.rect = siblingRect;
+ option.state = siblings.at(i) ? QStyle::State_Sibling : QStyle::State_None;
+
+ if (isItemSibling) {
+ option.state |= QStyle::State_Item;
+ if (m_isExpandable) {
+ option.state |= QStyle::State_Children;
+ }
+ if (data()["isExpanded"].toBool()) {
+ option.state |= QStyle::State_Open;
+ }
+ isItemSibling = false;
+ }
+
+ style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter);
+
+ siblingRect.translate(-siblingRect.width(), 0);
+ }
+}
+
QPixmap KFileItemListWidget::pixmapForIcon(const QString& name, int size)
{
const KIcon icon(name);
diff --git a/dolphin/src/kitemviews/kfileitemlistwidget.h b/dolphin/src/kitemviews/kfileitemlistwidget.h
index 4a44a84..afb0f01 100644
--- a/dolphin/src/kitemviews/kfileitemlistwidget.h
+++ b/dolphin/src/kitemviews/kfileitemlistwidget.h
@@ -86,6 +86,7 @@ protected:
virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
virtual void hoveredChanged(bool hovered);
virtual void selectedChanged(bool selected);
+ virtual void siblingsInformationChanged(const QBitArray& current, const QBitArray& previous);
virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
virtual void showEvent(QShowEvent* event);
virtual void hideEvent(QHideEvent* event);
@@ -119,6 +120,7 @@ private:
void updateAdditionalInfoTextColor();
void drawPixmap(QPainter* painter, const QPixmap& pixmap);
+ void drawSiblingsInformation(QPainter* painter);
static QPixmap pixmapForIcon(const QString& name, int size);
static TextId roleTextId(const QByteArray& role);
diff --git a/dolphin/src/kitemviews/kfileitemmodel.cpp b/dolphin/src/kitemviews/kfileitemmodel.cpp
index e0ae033..f9ba397 100644
--- a/dolphin/src/kitemviews/kfileitemmodel.cpp
+++ b/dolphin/src/kitemviews/kfileitemmodel.cpp
@@ -50,7 +50,7 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) :
m_pendingItemsToInsert(),
m_pendingEmitLoadingCompleted(false),
m_groups(),
- m_rootExpansionLevel(UninitializedRootExpansionLevel),
+ m_expandedParentsCountRoot(UninitializedExpandedParentsCountRoot),
m_expandedUrls(),
m_urlsToExpand()
{
@@ -265,22 +265,22 @@ QString KFileItemModel::roleDescription(const QByteArray& role) const
QString descr;
switch (roleIndex(role)) {
- case NameRole: descr = i18nc("@item:intable", "Name"); break;
- case SizeRole: descr = i18nc("@item:intable", "Size"); break;
- case DateRole: descr = i18nc("@item:intable", "Date"); break;
- case PermissionsRole: descr = i18nc("@item:intable", "Permissions"); break;
- case OwnerRole: descr = i18nc("@item:intable", "Owner"); break;
- case GroupRole: descr = i18nc("@item:intable", "Group"); break;
- case TypeRole: descr = i18nc("@item:intable", "Type"); break;
- case DestinationRole: descr = i18nc("@item:intable", "Destination"); break;
- case PathRole: descr = i18nc("@item:intable", "Path"); break;
- case CommentRole: descr = i18nc("@item:intable", "Comment"); break;
- case TagsRole: descr = i18nc("@item:intable", "Tags"); break;
- case RatingRole: descr = i18nc("@item:intable", "Rating"); break;
- case NoRole: break;
- case IsDirRole: break;
- case IsExpandedRole: break;
- case ExpansionLevelRole: break;
+ case NameRole: descr = i18nc("@item:intable", "Name"); break;
+ case SizeRole: descr = i18nc("@item:intable", "Size"); break;
+ case DateRole: descr = i18nc("@item:intable", "Date"); break;
+ case PermissionsRole: descr = i18nc("@item:intable", "Permissions"); break;
+ case OwnerRole: descr = i18nc("@item:intable", "Owner"); break;
+ case GroupRole: descr = i18nc("@item:intable", "Group"); break;
+ case TypeRole: descr = i18nc("@item:intable", "Type"); break;
+ case DestinationRole: descr = i18nc("@item:intable", "Destination"); break;
+ case PathRole: descr = i18nc("@item:intable", "Path"); break;
+ case CommentRole: descr = i18nc("@item:intable", "Comment"); break;
+ case TagsRole: descr = i18nc("@item:intable", "Tags"); break;
+ case RatingRole: descr = i18nc("@item:intable", "Rating"); break;
+ case NoRole: break;
+ case IsDirRole: break;
+ case IsExpandedRole: break;
+ case ExpandedParentsCountRole: break;
default: Q_ASSERT(false); break;
}
@@ -295,22 +295,22 @@ QList<QPair<int, QVariant> > KFileItemModel::groups() const
timer.start();
#endif
switch (roleIndex(sortRole())) {
- case NameRole: m_groups = nameRoleGroups(); break;
- case SizeRole: m_groups = sizeRoleGroups(); break;
- case DateRole: m_groups = dateRoleGroups(); break;
- case PermissionsRole: m_groups = permissionRoleGroups(); break;
- case OwnerRole: m_groups = genericStringRoleGroups("owner"); break;
- case GroupRole: m_groups = genericStringRoleGroups("group"); break;
- case TypeRole: m_groups = genericStringRoleGroups("type"); break;
- case DestinationRole: m_groups = genericStringRoleGroups("destination"); break;
- case PathRole: m_groups = genericStringRoleGroups("path"); break;
- case CommentRole: m_groups = genericStringRoleGroups("comment"); break;
- case TagsRole: m_groups = genericStringRoleGroups("tags"); break;
- case RatingRole: m_groups = ratingRoleGroups(); break;
- case NoRole: break;
- case IsDirRole: break;
- case IsExpandedRole: break;
- case ExpansionLevelRole: break;
+ case NameRole: m_groups = nameRoleGroups(); break;
+ case SizeRole: m_groups = sizeRoleGroups(); break;
+ case DateRole: m_groups = dateRoleGroups(); break;
+ case PermissionsRole: m_groups = permissionRoleGroups(); break;
+ case OwnerRole: m_groups = genericStringRoleGroups("owner"); break;
+ case GroupRole: m_groups = genericStringRoleGroups("group"); break;
+ case TypeRole: m_groups = genericStringRoleGroups("type"); break;
+ case DestinationRole: m_groups = genericStringRoleGroups("destination"); break;
+ case PathRole: m_groups = genericStringRoleGroups("path"); break;
+ case CommentRole: m_groups = genericStringRoleGroups("comment"); break;
+ case TagsRole: m_groups = genericStringRoleGroups("tags"); break;
+ case RatingRole: m_groups = ratingRoleGroups(); break;
+ case NoRole: break;
+ case IsDirRole: break;
+ case IsExpandedRole: break;
+ case ExpandedParentsCountRole: break;
default: Q_ASSERT(false); break;
}
@@ -375,8 +375,8 @@ void KFileItemModel::setRoles(const QSet<QByteArray>& roles)
m_roles = roles;
if (count() > 0) {
- const bool supportedExpanding = m_requestRole[ExpansionLevelRole];
- const bool willSupportExpanding = roles.contains("expansionLevel");
+ const bool supportedExpanding = m_requestRole[ExpandedParentsCountRole];
+ const bool willSupportExpanding = roles.contains("expandedParentsCount");
if (supportedExpanding && !willSupportExpanding) {
// No expanding is supported anymore. Take care to delete all items that have an expansion level
// that is not 0 (and hence are part of an expanded item).
@@ -439,9 +439,9 @@ bool KFileItemModel::setExpanded(int index, bool expanded)
}
KFileItemList itemsToRemove;
- const int expansionLevel = data(index)["expansionLevel"].toInt();
+ const int expandedParentsCount = data(index)["expandedParentsCount"].toInt();
++index;
- while (index < count() && data(index)["expansionLevel"].toInt() > expansionLevel) {
+ while (index < count() && data(index)["expandedParentsCount"].toInt() > expandedParentsCount) {
itemsToRemove.append(m_itemData.at(index)->item);
++index;
}
@@ -468,6 +468,14 @@ bool KFileItemModel::isExpandable(int index) const
return false;
}
+int KFileItemModel::expandedParentsCount(int index) const
+{
+ if (index >= 0 && index < count()) {
+ return m_itemData.at(index)->values.value("expandedParentsCount").toInt();
+ }
+ return 0;
+}
+
QSet<KUrl> KFileItemModel::expandedUrls() const
{
return m_expandedUrls;
@@ -687,7 +695,7 @@ void KFileItemModel::slotNewItems(const KFileItemList& items)
{
Q_ASSERT(!items.isEmpty());
- if (m_requestRole[ExpansionLevelRole] && m_rootExpansionLevel >= 0) {
+ if (m_requestRole[ExpandedParentsCountRole] && m_expandedParentsCountRoot >= 0) {
// To be able to compare whether the new items may be inserted as children
// of a parent item the pending items must be added to the model first.
dispatchPendingItemsToInsert();
@@ -747,7 +755,7 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items)
dispatchPendingItemsToInsert();
KFileItemList itemsToRemove = items;
- if (m_requestRole[ExpansionLevelRole] && m_rootExpansionLevel >= 0) {
+ if (m_requestRole[ExpandedParentsCountRole] && m_expandedParentsCountRoot >= 0) {
// Assure that removing a parent item also results in removing all children
foreach (const KFileItem& item, items) {
itemsToRemove.append(childItems(item));
@@ -842,7 +850,7 @@ void KFileItemModel::slotClear()
m_resortAllItemsTimer->stop();
m_pendingItemsToInsert.clear();
- m_rootExpansionLevel = UninitializedRootExpansionLevel;
+ m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot;
const int removedCount = m_itemData.count();
if (removedCount > 0) {
@@ -1031,7 +1039,7 @@ void KFileItemModel::removeItems(const KFileItemList& items)
}
if (count() <= 0) {
- m_rootExpansionLevel = UninitializedRootExpansionLevel;
+ m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot;
}
itemRanges << KItemRange(removedAtIndex, removedCount);
@@ -1049,8 +1057,8 @@ QList<KFileItemModel::ItemData*> KFileItemModel::createItemDataList(const KFileI
itemData->values = retrieveData(item);
itemData->parent = 0;
- const bool determineParent = m_requestRole[ExpansionLevelRole]
- && itemData->values["expansionLevel"].toInt() > 0;
+ const bool determineParent = m_requestRole[ExpandedParentsCountRole]
+ && itemData->values["expandedParentsCount"].toInt() > 0;
if (determineParent) {
KUrl parentUrl = item.url().upUrl();
parentUrl.adjustPath(KUrl::RemoveTrailingSlash);
@@ -1075,17 +1083,17 @@ void KFileItemModel::removeExpandedItems()
const int maxIndex = m_itemData.count() - 1;
for (int i = 0; i <= maxIndex; ++i) {
const ItemData* itemData = m_itemData.at(i);
- if (itemData->values.value("expansionLevel").toInt() > 0) {
+ if (itemData->values.value("expandedParentsCount").toInt() > 0) {
expandedItems.append(itemData->item);
}
}
- // The m_rootExpansionLevel may not get reset before all items with
- // a bigger expansionLevel have been removed.
- Q_ASSERT(m_rootExpansionLevel >= 0);
+ // The m_expandedParentsCountRoot may not get reset before all items with
+ // a bigger count have been removed.
+ Q_ASSERT(m_expandedParentsCountRoot >= 0);
removeItems(expandedItems);
- m_rootExpansionLevel = UninitializedRootExpansionLevel;
+ m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot;
m_expandedUrls.clear();
}
@@ -1115,7 +1123,7 @@ KFileItemModel::Role KFileItemModel::roleIndex(const QByteArray& role) const
rolesHash.insert("isDir", IsDirRole);
rolesHash.insert("isExpanded", IsExpandedRole);
rolesHash.insert("isExpandable", IsExpandableRole);
- rolesHash.insert("expansionLevel", ExpansionLevelRole);
+ rolesHash.insert("expandedParentsCount", ExpandedParentsCountRole);
}
return rolesHash.value(role, NoRole);
}
@@ -1139,7 +1147,7 @@ QByteArray KFileItemModel::roleByteArray(Role role) const
"isDir",
"isExpanded",
"isExpandable",
- "expansionLevel"
+ "expandedParentsCount"
};
return roles[role];
}
@@ -1219,28 +1227,28 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item)
data.insert("isExpandable", item.isDir() && item.url() == item.targetUrl());
}
- if (m_requestRole[ExpansionLevelRole]) {
- if (m_rootExpansionLevel == UninitializedRootExpansionLevel && m_dirLister.data()) {
+ if (m_requestRole[ExpandedParentsCountRole]) {
+ if (m_expandedParentsCountRoot == UninitializedExpandedParentsCountRoot && m_dirLister.data()) {
const KUrl rootUrl = m_dirLister.data()->url();
const QString protocol = rootUrl.protocol();
- const bool forceRootExpansionLevel = (protocol == QLatin1String("trash") ||
- protocol == QLatin1String("nepomuk") ||
- protocol == QLatin1String("remote") ||
- protocol.contains(QLatin1String("search")));
- if (forceRootExpansionLevel) {
- m_rootExpansionLevel = ForceRootExpansionLevel;
+ const bool forceExpandedParentsCountRoot = (protocol == QLatin1String("trash") ||
+ protocol == QLatin1String("nepomuk") ||
+ protocol == QLatin1String("remote") ||
+ protocol.contains(QLatin1String("search")));
+ if (forceExpandedParentsCountRoot) {
+ m_expandedParentsCountRoot = ForceExpandedParentsCountRoot;
} else {
const QString rootDir = rootUrl.path(KUrl::AddTrailingSlash);
- m_rootExpansionLevel = rootDir.count('/');
+ m_expandedParentsCountRoot = rootDir.count('/');
}
}
- if (m_rootExpansionLevel == ForceRootExpansionLevel) {
- data.insert("expansionLevel", -1);
+ if (m_expandedParentsCountRoot == ForceExpandedParentsCountRoot) {
+ data.insert("expandedParentsCount", -1);
} else {
const QString dir = item.url().directory(KUrl::AppendTrailingSlash);
- const int level = dir.count('/') - m_rootExpansionLevel;
- data.insert("expansionLevel", level);
+ const int level = dir.count('/') - m_expandedParentsCountRoot;
+ data.insert("expandedParentsCount", level);
}
}
@@ -1259,8 +1267,8 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b) const
{
int result = 0;
- if (m_rootExpansionLevel >= 0) {
- result = expansionLevelsCompare(a, b);
+ if (m_expandedParentsCountRoot >= 0) {
+ result = expandedParentsCountCompare(a, b);
if (result != 0) {
// The items have parents with different expansion levels
return (sortOrder() == Qt::AscendingOrder) ? result < 0 : result > 0;
@@ -1528,7 +1536,7 @@ int KFileItemModel::stringCompare(const QString& a, const QString& b) const
: QString::compare(a, b, Qt::CaseSensitive);
}
-int KFileItemModel::expansionLevelsCompare(const ItemData* a, const ItemData* b) const
+int KFileItemModel::expandedParentsCountCompare(const ItemData* a, const ItemData* b) const
{
const KUrl urlA = a->item.url();
const KUrl urlB = b->item.url();
@@ -1935,9 +1943,9 @@ KFileItemList KFileItemModel::childItems(const KFileItem& item) const
int index = m_items.value(item.url(), -1);
if (index >= 0) {
- const int parentLevel = m_itemData.at(index)->values.value("expansionLevel").toInt();
+ const int parentLevel = m_itemData.at(index)->values.value("expandedParentsCount").toInt();
++index;
- while (index < m_itemData.count() && m_itemData.at(index)->values.value("expansionLevel").toInt() > parentLevel) {
+ while (index < m_itemData.count() && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > parentLevel) {
items.append(m_itemData.at(index)->item);
++index;
}
diff --git a/dolphin/src/kitemviews/kfileitemmodel.h b/dolphin/src/kitemviews/kfileitemmodel.h
index a792b08..6cc53f1 100644
--- a/dolphin/src/kitemviews/kfileitemmodel.h
+++ b/dolphin/src/kitemviews/kfileitemmodel.h
@@ -139,6 +139,7 @@ public:
virtual bool setExpanded(int index, bool expanded);
virtual bool isExpanded(int index) const;
virtual bool isExpandable(int index) const;
+ virtual int expandedParentsCount(int index) const;
QSet<KUrl> expandedUrls() const;
@@ -208,7 +209,7 @@ private:
IsDirRole,
IsExpandedRole,
IsExpandableRole,
- ExpansionLevelRole,
+ ExpandedParentsCountRole,
RolesCount // Mandatory last entry
};
@@ -258,7 +259,7 @@ private:
bool lessThan(const ItemData* a, const ItemData* b) const;
/**
- * Helper method for lessThan() and expansionLevelsCompare(): Compares
+ * Helper method for lessThan() and expandedParentsCountCompare(): Compares
* the passed item-data using m_sortRole as criteria. Both items must
* have the same parent item, otherwise the comparison will be wrong.
*/
@@ -296,10 +297,10 @@ private:
* is not sufficient, it is also important to check the hierarchy for having
* a correct order like shown in a tree.
*/
- int expansionLevelsCompare(const ItemData* a, const ItemData* b) const;
+ int expandedParentsCountCompare(const ItemData* a, const ItemData* b) const;
/**
- * Helper method for expansionLevelCompare().
+ * Helper method for expandedParentsCountCompare().
*/
QString subPath(const KFileItem& item,
const QString& itemPath,
@@ -358,19 +359,19 @@ private:
mutable QList<QPair<int, QVariant> > m_groups;
// Stores the smallest expansion level of the root-URL. Is required to calculate
- // the "expansionLevel" role in an efficient way. A value < 0 indicates a
+ // the "expandedParentsCount" role in an efficient way. A value < 0 indicates a
// special meaning:
- enum RootExpansionLevelTypes
+ enum ExpandedParentsCountRootTypes
{
- // m_rootExpansionLevel is uninitialized and must be determined by checking
+ // m_expandedParentsCountRoot is uninitialized and must be determined by checking
// the root URL from the KDirLister.
- UninitializedRootExpansionLevel = -1,
- // All items should be forced to get an expansion level of 0 even if they
+ UninitializedExpandedParentsCountRoot = -1,
+ // All items should be forced to get an expanded parents count of 0 even if they
// represent child items. This is useful for slaves that provide no parent items
// for child items like e.g. the search IO slaves.
- ForceRootExpansionLevel = -2
+ ForceExpandedParentsCountRoot = -2
};
- mutable int m_rootExpansionLevel;
+ mutable int m_expandedParentsCountRoot;
// Stores the URLs of the expanded folders.
QSet<KUrl> m_expandedUrls;
@@ -384,7 +385,7 @@ private:
inline bool KFileItemModel::isChildItem(int index) const
{
- return m_requestRole[ExpansionLevelRole] && m_itemData.at(index)->values.value("expansionLevel").toInt() > 0;
+ return m_requestRole[ExpandedParentsCountRole] && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > 0;
}
#endif
diff --git a/dolphin/src/kitemviews/kitemlistview.cpp b/dolphin/src/kitemviews/kitemlistview.cpp
index 323e674..de80819 100644
--- a/dolphin/src/kitemviews/kitemlistview.cpp
+++ b/dolphin/src/kitemviews/kitemlistview.cpp
@@ -1346,6 +1346,16 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
const int lastVisibleIndex = m_layouter->lastVisibleIndex();
+ int firstExpansionIndex = -1;
+ int lastExpansionIndex = -1;
+ const bool supportsExpanding = supportsItemExpanding();
+ if (supportsExpanding && changedCount != 0) {
+ // Any inserting or removing of items might result in changing the siblings-information
+ // of other visible items.
+ firstExpansionIndex = firstVisibleIndex;
+ lastExpansionIndex = lastVisibleIndex;
+ }
+
QList<int> reusableItems = recycleInvisibleItems(firstVisibleIndex, lastVisibleIndex, hint);
// Assure that for each visible item a KItemListWidget is available. KItemListWidget
@@ -1390,6 +1400,13 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
}
applyNewPos = false;
}
+
+ if (supportsExpanding && changedCount == 0) {
+ if (firstExpansionIndex < 0) {
+ firstExpansionIndex = i;
+ }
+ lastExpansionIndex = i;
+ }
}
if (animate) {
@@ -1452,6 +1469,10 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
recycleWidget(m_visibleItems.value(index));
}
+ if (supportsExpanding) {
+ updateSiblingsInformation(firstExpansionIndex, lastExpansionIndex);
+ }
+
if (m_grouped) {
// Update the layout of all visible group headers
QHashIterator<KItemListWidget*, KItemListGroupHeader*> it(m_visibleGroups);
@@ -1627,6 +1648,7 @@ void KItemListView::updateWidgetProperties(KItemListWidget* widget, int index)
widget->setEnabledSelectionToggle(enabledSelectionToggles());
widget->setIndex(index);
widget->setData(m_model->data(index));
+ widget->setSiblingsInformation(QBitArray());
}
void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget)
@@ -1968,6 +1990,112 @@ void KItemListView::updateGroupHeaderHeight()
updateVisibleGroupHeaders();
}
+void KItemListView::updateSiblingsInformation(int firstIndex, int lastIndex)
+{
+ const int firstVisibleIndex = m_layouter->firstVisibleIndex();
+ const int lastVisibleIndex = m_layouter->lastVisibleIndex();
+ const bool isRangeVisible = firstIndex >= 0 &&
+ lastIndex >= firstIndex &&
+ lastIndex >= firstVisibleIndex &&
+ firstIndex <= lastVisibleIndex;
+ if (!isRangeVisible) {
+ return;
+ }
+
+ int previousParents = 0;
+ QBitArray previousSiblings;
+
+ // The rootIndex describes the first index where the siblings get
+ // calculated from. For the calculation the upper most parent item
+ // is required. For performance reasons it is checked first whether
+ // the visible items before or after the current range already
+ // contain a siblings information which can be used as base.
+ int rootIndex = firstIndex;
+
+ KItemListWidget* widget = m_visibleItems.value(firstIndex - 1);
+ if (!widget) {
+ // There is no visible widget before the range, check whether there
+ // is one after the range:
+ widget = m_visibleItems.value(lastIndex + 1);
+ if (widget) {
+ // The sibling information of the widget may only be used if
+ // all items of the range have the same number of parents.
+ const int parents = m_model->expandedParentsCount(lastIndex + 1);
+ for (int i = lastIndex; i >= firstIndex; --i) {
+ if (m_model->expandedParentsCount(i) != parents) {
+ widget = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (widget) {
+ // Performance optimization: Use the sibling information of the visible
+ // widget beside the given range.
+ previousSiblings = widget->siblingsInformation();
+ if (previousSiblings.isEmpty()) {
+ return;
+ }
+ previousParents = previousSiblings.count() - 1;
+ previousSiblings.truncate(previousParents);
+ } else {
+ // Potentially slow path: Go back to the upper most parent of firstIndex
+ // to be able to calculate the initial value for the siblings.
+ while (rootIndex > 0 && m_model->expandedParentsCount(rootIndex) > 0) {
+ --rootIndex;
+ }
+ }
+
+ for (int i = rootIndex; i <= lastIndex; ++i) {
+ // Update the parent-siblings in case if the current item represents
+ // a child or an upper parent.
+ const int currentParents = m_model->expandedParentsCount(i);
+ if (previousParents < currentParents) {
+ previousParents = currentParents;
+ previousSiblings.resize(currentParents);
+ previousSiblings.setBit(currentParents - 1, hasSiblingSuccessor(i - 1));
+ } else if (previousParents > currentParents) {
+ previousParents = currentParents;
+ previousSiblings.truncate(currentParents);
+ }
+
+ if (i >= firstIndex) {
+ // The index represents a visible item. Apply the parent-siblings
+ // and update the sibling of the current item.
+ KItemListWidget* widget = m_visibleItems.value(i);
+ if (!widget) {
+ continue;
+ }
+
+ QBitArray siblings = previousSiblings;
+ siblings.resize(siblings.count() + 1);
+ siblings.setBit(siblings.count() - 1, hasSiblingSuccessor(i));
+
+ widget->setSiblingsInformation(siblings);
+ }
+ }
+}
+
+bool KItemListView::hasSiblingSuccessor(int index) const
+{
+ const int parentsCount = m_model->expandedParentsCount(index);
+ ++index;
+
+ const int itemCount = m_model->count();
+ while (index < itemCount) {
+ const int currentParentsCount = m_model->expandedParentsCount(index);
+ if (currentParentsCount == parentsCount) {
+ return true;
+ } else if (currentParentsCount < parentsCount) {
+ return false;
+ }
+ ++index;
+ }
+
+ return false;
+}
+
int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc)
{
int inc = 0;
diff --git a/dolphin/src/kitemviews/kitemlistview.h b/dolphin/src/kitemviews/kitemlistview.h
index 6ed714b..dbb746d 100644
--- a/dolphin/src/kitemviews/kitemlistview.h
+++ b/dolphin/src/kitemviews/kitemlistview.h
@@ -497,6 +497,20 @@ private:
void updateGroupHeaderHeight();
/**
+ * Updates the siblings-information for all visible items that are inside
+ * the range of \p firstIndex and \p lastIndex.
+ * @see KItemListWidget::setSiblingsInformation()
+ */
+ void updateSiblingsInformation(int firstIndex, int lastIndex);
+
+ /**
+ * Helper method for updateExpansionIndicators().
+ * @return True if the item with the index \a index has a sibling successor
+ * (= the item is not the last item of the current hierarchy).
+ */
+ bool hasSiblingSuccessor(int index) const;
+
+ /**
* Helper function for triggerAutoScrolling().
* @param pos Logical position of the mouse relative to the range.
* @param range Range of the visible area.
diff --git a/dolphin/src/kitemviews/kitemlistwidget.cpp b/dolphin/src/kitemviews/kitemlistwidget.cpp
index 3d593f7..24a3f07 100644
--- a/dolphin/src/kitemviews/kitemlistwidget.cpp
+++ b/dolphin/src/kitemviews/kitemlistwidget.cpp
@@ -46,6 +46,7 @@ KItemListWidget::KItemListWidget(QGraphicsItem* parent) :
m_visibleRoles(),
m_visibleRolesSizes(),
m_styleOption(),
+ m_siblingsInfo(),
m_hoverOpacity(0),
m_hoverCache(0),
m_hoverAnimation(0),
@@ -92,6 +93,7 @@ void KItemListWidget::setData(const QHash<QByteArray, QVariant>& data,
}
dataChanged(m_data, roles);
}
+ update();
}
QHash<QByteArray, QVariant> KItemListWidget::data() const
@@ -167,7 +169,9 @@ void KItemListWidget::setVisibleRoles(const QList<QByteArray>& roles)
{
const QList<QByteArray> previousRoles = m_visibleRoles;
m_visibleRoles = roles;
+
visibleRolesChanged(roles, previousRoles);
+ update();
}
QList<QByteArray> KItemListWidget::visibleRoles() const
@@ -179,7 +183,9 @@ void KItemListWidget::setVisibleRolesSizes(const QHash<QByteArray, QSizeF> roles
{
const QHash<QByteArray, QSizeF> previousRolesSizes = m_visibleRolesSizes;
m_visibleRolesSizes = rolesSizes;
+
visibleRolesSizesChanged(rolesSizes, previousRolesSizes);
+ update();
}
QHash<QByteArray, QSizeF> KItemListWidget::visibleRolesSizes() const
@@ -194,6 +200,7 @@ void KItemListWidget::setStyleOption(const KItemListStyleOption& option)
m_styleOption = option;
styleOptionChanged(option, previous);
+ update();
}
const KItemListStyleOption& KItemListWidget::styleOption() const
@@ -208,7 +215,6 @@ void KItemListWidget::setSelected(bool selected)
if (m_selectionToggle) {
m_selectionToggle->setChecked(selected);
}
-
selectedChanged(selected);
update();
}
@@ -223,7 +229,6 @@ void KItemListWidget::setCurrent(bool current)
{
if (m_current != current) {
m_current = current;
-
currentChanged(current);
update();
}
@@ -265,7 +270,6 @@ void KItemListWidget::setHovered(bool hovered)
m_hoverAnimation->start();
hoveredChanged(hovered);
-
update();
}
@@ -301,6 +305,19 @@ bool KItemListWidget::enabledSelectionToggle() const
return m_enabledSelectionToggle;
}
+void KItemListWidget::setSiblingsInformation(const QBitArray& siblings)
+{
+ const QBitArray previous = m_siblingsInfo;
+ m_siblingsInfo = siblings;
+ siblingsInformationChanged(m_siblingsInfo, previous);
+ update();
+}
+
+QBitArray KItemListWidget::siblingsInformation() const
+{
+ return m_siblingsInfo;
+}
+
bool KItemListWidget::contains(const QPointF& point) const
{
if (!QGraphicsWidget::contains(point)) {
@@ -328,7 +345,6 @@ void KItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
{
Q_UNUSED(current);
Q_UNUSED(roles);
- update();
}
void KItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
@@ -336,7 +352,6 @@ void KItemListWidget::visibleRolesChanged(const QList<QByteArray>& current,
{
Q_UNUSED(current);
Q_UNUSED(previous);
- update();
}
void KItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current,
@@ -344,7 +359,6 @@ void KItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>&
{
Q_UNUSED(current);
Q_UNUSED(previous);
- update();
}
void KItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
@@ -352,7 +366,6 @@ void KItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
{
Q_UNUSED(current);
Q_UNUSED(previous);
- update();
}
void KItemListWidget::currentChanged(bool current)
@@ -375,6 +388,12 @@ void KItemListWidget::alternatingBackgroundColorsChanged(bool enabled)
Q_UNUSED(enabled);
}
+void KItemListWidget::siblingsInformationChanged(const QBitArray& current, const QBitArray& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
{
QGraphicsWidget::resizeEvent(event);
diff --git a/dolphin/src/kitemviews/kitemlistwidget.h b/dolphin/src/kitemviews/kitemlistwidget.h
index 02e5998..20efa7c 100644
--- a/dolphin/src/kitemviews/kitemlistwidget.h
+++ b/dolphin/src/kitemviews/kitemlistwidget.h
@@ -27,6 +27,7 @@
#include <kitemviews/kitemliststyleoption.h>
+#include <QBitArray>
#include <QGraphicsWidget>
#include <QStyle>
@@ -88,6 +89,16 @@ public:
bool enabledSelectionToggle() const;
/**
+ * Sets the sibling information for the item and all of its parents.
+ * The sibling information of the upper most parent is represented by
+ * the first bit, the sibling information of the item by the last bit.
+ * The sibling information is useful for drawing the branches in
+ * tree views.
+ */
+ void setSiblingsInformation(const QBitArray& siblings);
+ QBitArray siblingsInformation() const;
+
+ /**
* @return True if \a point is inside KItemListWidget::hoverRect(),
* KItemListWidget::textRect(), KItemListWidget::selectionToggleRect()
* or KItemListWidget::expansionToggleRect().
@@ -128,6 +139,7 @@ protected:
virtual void selectedChanged(bool selected);
virtual void hoveredChanged(bool hovered);
virtual void alternatingBackgroundColorsChanged(bool enabled);
+ virtual void siblingsInformationChanged(const QBitArray& current, const QBitArray& previous);
virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
/**
@@ -158,6 +170,7 @@ private:
QList<QByteArray> m_visibleRoles;
QHash<QByteArray, QSizeF> m_visibleRolesSizes;
KItemListStyleOption m_styleOption;
+ QBitArray m_siblingsInfo;
qreal m_hoverOpacity;
mutable QPixmap* m_hoverCache;
diff --git a/dolphin/src/kitemviews/kitemmodelbase.cpp b/dolphin/src/kitemviews/kitemmodelbase.cpp
index e2b86d8..c13c9f8 100644
--- a/dolphin/src/kitemviews/kitemmodelbase.cpp
+++ b/dolphin/src/kitemviews/kitemmodelbase.cpp
@@ -128,6 +128,12 @@ bool KItemModelBase::isExpandable(int index) const
return false;
}
+int KItemModelBase::expandedParentsCount(int index) const
+{
+ Q_UNUSED(index);
+ return 0;
+}
+
QMimeData* KItemModelBase::createMimeData(const QSet<int>& indexes) const
{
Q_UNUSED(indexes);
diff --git a/dolphin/src/kitemviews/kitemmodelbase.h b/dolphin/src/kitemviews/kitemmodelbase.h
index 1dffaf8..de847a9 100644
--- a/dolphin/src/kitemviews/kitemmodelbase.h
+++ b/dolphin/src/kitemviews/kitemmodelbase.h
@@ -146,6 +146,12 @@ public:
virtual bool isExpandable(int index) const;
/**
+ * @return Number of expanded parent items for the item with the given index.
+ * Per default 0 is returned.
+ */
+ virtual int expandedParentsCount(int index) const;
+
+ /**
* @return MIME-data for the items given by \a indexes. The default implementation
* returns 0. The ownership of the returned instance is in the hand of the
* caller of this method.
diff --git a/dolphin/src/tests/kfileitemmodeltest.cpp b/dolphin/src/tests/kfileitemmodeltest.cpp
index d0accd6..ea67b85 100644
--- a/dolphin/src/tests/kfileitemmodeltest.cpp
+++ b/dolphin/src/tests/kfileitemmodeltest.cpp
@@ -373,7 +373,7 @@ void KFileItemModelTest::testExpandItems()
// yields the correct result for "a/a/1" and "a/a-1/", whis is non-trivial because they share the
// first three characters.
QSet<QByteArray> modelRoles = m_model->roles();
- modelRoles << "isExpanded" << "isExpandable" << "expansionLevel";
+ modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
m_model->setRoles(modelRoles);
QStringList files;
@@ -490,7 +490,7 @@ void KFileItemModelTest::testExpandParentItems()
// a2/b2/c2/
// a2/b2/c2/d2/
QSet<QByteArray> modelRoles = m_model->roles();
- modelRoles << "isExpanded" << "isExpandable" << "expansionLevel";
+ modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
m_model->setRoles(modelRoles);
QStringList files;
@@ -665,7 +665,7 @@ void KFileItemModelTest::testExpansionLevelsCompare()
b.item = itemB;
b.parent = 0;
- QCOMPARE(m_model->expansionLevelsCompare(&a, &b), result);
+ QCOMPARE(m_model->expandedParentsCountCompare(&a, &b), result);
}
void KFileItemModelTest::testIndexForKeyboardSearch()