m_visibleItems(),
m_visibleGroups(),
m_visibleCells(),
- m_sizeHintResolver(nullptr),
m_layouter(nullptr),
m_animation(nullptr),
- m_layoutTimer(nullptr),
m_oldScrollOffset(0),
m_oldMaximumScrollOffset(0),
m_oldItemOffset(0),
m_header(nullptr),
m_headerWidget(nullptr),
m_indicatorAnimation(nullptr),
- m_dropIndicator()
+ m_dropIndicator(),
+ m_sizeHintResolver(nullptr)
{
setAcceptHoverEvents(true);
setAcceptTouchEvents(true);
connect(m_animation, &KItemListViewAnimation::finished,
this, &KItemListView::slotAnimationFinished);
- m_layoutTimer = new QTimer(this);
- m_layoutTimer->setInterval(300);
- m_layoutTimer->setSingleShot(true);
- connect(m_layoutTimer, &QTimer::timeout, this, &KItemListView::slotLayoutTimerFinished);
-
m_rubberBand = new KItemListRubberBand(this);
connect(m_rubberBand, &KItemListRubberBand::activationChanged, this, &KItemListView::slotRubberBandActivationChanged);
const KItemListWidget* widget = it.value();
const QPointF mappedPos = widget->mapFromItem(this, pos);
- if (widget->contains(mappedPos)) {
+ if (widget->contains(mappedPos) || widget->selectionRect().contains(mappedPos)) {
return it.key();
}
}
return m_supportsItemExpanding;
}
+void KItemListView::setHighlightEntireRow(bool highlightEntireRow)
+{
+ if (m_highlightEntireRow != highlightEntireRow) {
+ m_highlightEntireRow = highlightEntireRow;
+ onHighlightEntireRowChanged(highlightEntireRow);
+ }
+}
+
+bool KItemListView::highlightEntireRow() const
+{
+ return m_highlightEntireRow;
+}
+
+void KItemListView::setAlternateBackgrounds(bool alternate)
+{
+ if (m_alternateBackgrounds != alternate) {
+ m_alternateBackgrounds = alternate;
+ updateAlternateBackgrounds();
+ }
+}
+
+bool KItemListView::alternateBackgrounds() const
+{
+ return m_alternateBackgrounds;
+}
+
QRectF KItemListView::itemRect(int index) const
{
return m_layouter->itemRect(index);
connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged,
this, &KItemListView::slotHeaderColumnWidthChanged);
+ connect(m_headerWidget, &KItemListHeaderWidget::leadingPaddingChanged,
+ this, &KItemListView::slotLeadingPaddingChanged);
connect(m_headerWidget, &KItemListHeaderWidget::columnMoved,
this, &KItemListView::slotHeaderColumnMoved);
connect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged,
} else if (!visible && m_headerWidget->isVisible()) {
disconnect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged,
this, &KItemListView::slotHeaderColumnWidthChanged);
+ disconnect(m_headerWidget, &KItemListHeaderWidget::leadingPaddingChanged,
+ this, &KItemListView::slotLeadingPaddingChanged);
disconnect(m_headerWidget, &KItemListHeaderWidget::columnMoved,
this, &KItemListView::slotHeaderColumnMoved);
disconnect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged,
size,
m_layouter->itemMargin());
- const bool alternateBackgroundsChanged = (m_visibleRoles.count() > 1) &&
+ const bool alternateBackgroundsChanged = m_alternateBackgrounds &&
(( m_itemSize.isEmpty() && !size.isEmpty()) ||
(!m_itemSize.isEmpty() && size.isEmpty()));
Q_UNUSED(previous)
}
+void KItemListView::onHighlightEntireRowChanged(bool highlightEntireRow)
+{
+ Q_UNUSED(highlightEntireRow)
+}
+
void KItemListView::onSupportsItemExpandingChanged(bool supportsExpanding)
{
Q_UNUSED(supportsExpanding)
if (updateSizeHints) {
m_sizeHintResolver->itemsChanged(index, count, roles);
m_layouter->markAsDirty();
-
- if (!m_layoutTimer->isActive()) {
- m_layoutTimer->start();
- }
}
// Apply the changed roles to the visible item-widgets
ev.setLastRow(itemRange.index + itemRange.count);
QAccessible::updateAccessibility(&ev);
}
+
+ doLayout(NoAnimation);
}
void KItemListView::slotGroupsChanged()
KItemListWidget* itemListWidget = qobject_cast<KItemListWidget*>(widget);
Q_ASSERT(itemListWidget);
- switch (type) {
- case KItemListViewAnimation::DeleteAnimation: {
+ if (type == KItemListViewAnimation::DeleteAnimation) {
// As we recycle the widget in this case it is important to assure that no
// other animation has been started. This is a convention in KItemListView and
// not a requirement defined by KItemListViewAnimation.
// been finished.
recycleGroupHeaderForWidget(itemListWidget);
widgetCreator()->recycle(itemListWidget);
- break;
- }
-
- case KItemListViewAnimation::CreateAnimation:
- case KItemListViewAnimation::MovingAnimation:
- case KItemListViewAnimation::ResizeAnimation: {
+ } else {
const int index = itemListWidget->index();
const bool invisible = (index < m_layouter->firstVisibleIndex()) ||
(index > m_layouter->lastVisibleIndex());
if (invisible && !m_animation->isStarted(itemListWidget)) {
recycleWidget(itemListWidget);
}
- break;
- }
-
- default: break;
}
}
-void KItemListView::slotLayoutTimerFinished()
-{
- m_layouter->setSize(geometry().size());
- doLayout(Animation);
-}
-
void KItemListView::slotRubberBandPosChanged()
{
update();
doLayout(NoAnimation);
}
+void KItemListView::slotLeadingPaddingChanged(qreal width)
+{
+ Q_UNUSED(width)
+ if (m_headerWidget->automaticColumnResizing()) {
+ applyAutomaticColumnWidths();
+ }
+ applyColumnWidthsFromHeader();
+ doLayout(NoAnimation);
+}
+
void KItemListView::slotHeaderColumnMoved(const QByteArray& role,
int currentIndex,
int previousIndex)
void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int changedCount)
{
- if (m_layoutTimer->isActive()) {
- m_layoutTimer->stop();
- }
-
if (m_activeTransactions > 0) {
if (hint == NoAnimation) {
// As soon as at least one property change should be done without animation,
Q_ASSERT(widget->index() == i);
widget->setVisible(true);
+ bool animateIconResizing = animate;
+
if (widget->size() != itemBounds.size()) {
// Resize the widget for the item to the changed size.
if (animate) {
} else {
widget->resize(itemBounds.size());
}
+ } else {
+ animateIconResizing = false;
+ }
+
+ const int newIconSize = widget->styleOption().iconSize;
+ if (widget->iconSize() != newIconSize) {
+ if (animateIconResizing) {
+ m_animation->start(widget, KItemListViewAnimation::IconResizeAnimation, newIconSize);
+ } else {
+ widget->setIconSize(newIconSize);
+ }
}
// Updating the cell-information must be done as last step: The decision whether the
bool KItemListView::useAlternateBackgrounds() const
{
- return m_itemSize.isEmpty() && m_visibleRoles.count() > 1;
+ return m_alternateBackgrounds && m_itemSize.isEmpty();
}
QHash<QByteArray, qreal> KItemListView::preferredColumnWidths(const KItemRangeList& itemRanges) const
void KItemListView::applyColumnWidthsFromHeader()
{
// Apply the new size to the layouter
- const qreal requiredWidth = columnWidthsSum();
+ const qreal requiredWidth = columnWidthsSum() + m_headerWidget->leadingPadding();
const QSizeF dynamicItemSize(qMax(size().width(), requiredWidth),
m_itemSize.height());
m_layouter->setItemSize(dynamicItemSize);
for (const QByteArray& role : qAsConst(m_visibleRoles)) {
widget->setColumnWidth(role, m_headerWidget->columnWidth(role));
}
+ widget->setLeadingPadding(m_headerWidget->leadingPadding());
}
void KItemListView::updatePreferredColumnWidths(const KItemRangeList& itemRanges)
qreal firstColumnWidth = m_headerWidget->columnWidth(firstRole);
QSizeF dynamicItemSize = m_itemSize;
- qreal requiredWidth = columnWidthsSum();
+ qreal requiredWidth = columnWidthsSum() + m_headerWidget->leadingPadding()
+ + m_headerWidget->leadingPadding(); // Adding the padding a second time so we have the same padding symmetrically on both sides of the view.
+ // This improves UX, looks better and increases the chances of users figuring out that the padding area can be used for deselecting and dropping files.
const qreal availableWidth = size().width();
if (requiredWidth < availableWidth) {
// Stretch the first column to use the whole remaining width