mirror of
https://invent.kde.org/system/dolphin
synced 2024-08-22 01:40:02 +00:00
Full row highlight implementation
This commit implements full-row selection and hover highlights for the details view mode. This commit also contains fixes for 444680, 444753, both uncovered during this change. BUG: 181438 BUG: 444680 BUG: 444753 FIXED-IN: 22.04
This commit is contained in:
parent
a286506405
commit
d383961719
|
@ -574,7 +574,7 @@ bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pressedIndex.has_value()) {
|
if (m_pressedIndex.has_value() && !m_view->rubberBand()->isActive()) {
|
||||||
// Check whether a dragging should be started
|
// Check whether a dragging should be started
|
||||||
if (event->buttons() & Qt::LeftButton) {
|
if (event->buttons() & Qt::LeftButton) {
|
||||||
const QPointF pos = transform.map(event->pos());
|
const QPointF pos = transform.map(event->pos());
|
||||||
|
@ -828,27 +828,76 @@ bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
KItemListWidget* oldHoveredWidget = hoveredWidget();
|
// We identify the widget whose expansionArea had been hovered before this hoverMoveEvent() triggered.
|
||||||
const QPointF pos = transform.map(event->pos());
|
// we can't use hoveredWidget() here (it handles the icon+text rect, not the expansion rect)
|
||||||
KItemListWidget* newHoveredWidget = widgetForPos(pos);
|
// like hoveredWidget(), we find the hovered widget for the expansion rect
|
||||||
|
const auto visibleItemListWidgets = m_view->visibleItemListWidgets();
|
||||||
|
const auto oldHoveredExpansionWidgetIterator = std::find_if(visibleItemListWidgets.begin(), visibleItemListWidgets.end(), [](auto &widget) {
|
||||||
|
return widget->expansionAreaHovered();
|
||||||
|
});
|
||||||
|
const auto oldHoveredExpansionWidget = oldHoveredExpansionWidgetIterator == visibleItemListWidgets.end() ?
|
||||||
|
std::nullopt : std::make_optional(*oldHoveredExpansionWidgetIterator);
|
||||||
|
|
||||||
if (oldHoveredWidget != newHoveredWidget) {
|
const auto unhoverOldHoveredWidget = [&]() {
|
||||||
if (oldHoveredWidget) {
|
if (auto oldHoveredWidget = hoveredWidget(); oldHoveredWidget) {
|
||||||
|
// handle the text+icon one
|
||||||
oldHoveredWidget->setHovered(false);
|
oldHoveredWidget->setHovered(false);
|
||||||
Q_EMIT itemUnhovered(oldHoveredWidget->index());
|
Q_EMIT itemUnhovered(oldHoveredWidget->index());
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (newHoveredWidget) {
|
const auto unhoverOldExpansionWidget = [&]() {
|
||||||
|
if (oldHoveredExpansionWidget) {
|
||||||
|
// then the expansion toggle
|
||||||
|
(*oldHoveredExpansionWidget)->setExpansionAreaHovered(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const QPointF pos = transform.map(event->pos());
|
||||||
|
if (KItemListWidget *newHoveredWidget = widgetForPos(pos); newHoveredWidget) {
|
||||||
|
// something got hovered, work out which part and set hover for the appropriate widget
|
||||||
|
const auto mappedPos = newHoveredWidget->mapFromItem(m_view, pos);
|
||||||
|
const bool isOnExpansionToggle = newHoveredWidget->expansionToggleRect().contains(mappedPos);
|
||||||
|
|
||||||
|
if (isOnExpansionToggle) {
|
||||||
|
// make sure we unhover the old one first if old!=new
|
||||||
|
if (oldHoveredExpansionWidget && *oldHoveredExpansionWidget != newHoveredWidget) {
|
||||||
|
(*oldHoveredExpansionWidget)->setExpansionAreaHovered(false);
|
||||||
|
}
|
||||||
|
// we also unhover any old icon+text hovers, in case the mouse movement from icon+text to expansion toggle is too fast (i.e. newHoveredWidget is never null between the transition)
|
||||||
|
unhoverOldHoveredWidget();
|
||||||
|
|
||||||
|
|
||||||
|
newHoveredWidget->setExpansionAreaHovered(true);
|
||||||
|
} else {
|
||||||
|
// make sure we unhover the old one first if old!=new
|
||||||
|
if (auto oldHoveredWidget = hoveredWidget(); oldHoveredWidget && oldHoveredWidget != newHoveredWidget) {
|
||||||
|
oldHoveredWidget->setHovered(false);
|
||||||
|
Q_EMIT itemUnhovered(oldHoveredWidget->index());
|
||||||
|
}
|
||||||
|
// we also unhover any old expansion toggle hovers, in case the mouse movement from expansion toggle to icon+text is too fast (i.e. newHoveredWidget is never null between the transition)
|
||||||
|
unhoverOldExpansionWidget();
|
||||||
|
|
||||||
|
const bool isOverIconAndText = newHoveredWidget->iconRect().contains(mappedPos) || newHoveredWidget->textRect().contains(mappedPos);
|
||||||
|
const bool hasMultipleSelection = m_selectionManager->selectedItems().count() > 1;
|
||||||
|
|
||||||
|
if (hasMultipleSelection && !isOverIconAndText) {
|
||||||
|
// In case we have multiple selections, clicking on any row will deselect the selection.
|
||||||
|
// So, as a visual cue for signalling that clicking anywhere won't select, but clear current highlights,
|
||||||
|
// we disable hover of the *row*(i.e. blank space to the right of the icon+text)
|
||||||
|
|
||||||
|
// (no-op in this branch for masked hover)
|
||||||
|
} else {
|
||||||
newHoveredWidget->setHovered(true);
|
newHoveredWidget->setHovered(true);
|
||||||
const QPointF mappedPos = newHoveredWidget->mapFromItem(m_view, pos);
|
|
||||||
newHoveredWidget->setHoverPosition(mappedPos);
|
newHoveredWidget->setHoverPosition(mappedPos);
|
||||||
Q_EMIT itemHovered(newHoveredWidget->index());
|
Q_EMIT itemHovered(newHoveredWidget->index());
|
||||||
}
|
}
|
||||||
} else if (oldHoveredWidget) {
|
|
||||||
const QPointF mappedPos = oldHoveredWidget->mapFromItem(m_view, pos);
|
|
||||||
oldHoveredWidget->setHoverPosition(mappedPos);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// unhover any currently hovered expansion and text+icon widgets
|
||||||
|
unhoverOldHoveredWidget();
|
||||||
|
unhoverOldExpansionWidget();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1303,10 +1352,7 @@ KItemListWidget* KItemListController::widgetForPos(const QPointF& pos) const
|
||||||
const auto widgets = m_view->visibleItemListWidgets();
|
const auto widgets = m_view->visibleItemListWidgets();
|
||||||
for (KItemListWidget* widget : widgets) {
|
for (KItemListWidget* widget : widgets) {
|
||||||
const QPointF mappedPos = widget->mapFromItem(m_view, pos);
|
const QPointF mappedPos = widget->mapFromItem(m_view, pos);
|
||||||
|
if (widget->contains(mappedPos) || widget->selectionRect().contains(mappedPos)) {
|
||||||
const bool hovered = widget->contains(mappedPos) &&
|
|
||||||
!widget->expansionToggleRect().contains(mappedPos);
|
|
||||||
if (hovered) {
|
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1447,6 +1493,7 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
|
||||||
|
|
||||||
const bool shiftPressed = modifiers & Qt::ShiftModifier;
|
const bool shiftPressed = modifiers & Qt::ShiftModifier;
|
||||||
const bool controlPressed = modifiers & Qt::ControlModifier;
|
const bool controlPressed = modifiers & Qt::ControlModifier;
|
||||||
|
const bool rightClick = buttons & Qt::RightButton;
|
||||||
|
|
||||||
// The previous selection is cleared if either
|
// The previous selection is cleared if either
|
||||||
// 1. The selection mode is SingleSelection, or
|
// 1. The selection mode is SingleSelection, or
|
||||||
|
@ -1459,8 +1506,32 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
|
||||||
const bool pressedItemAlreadySelected = m_pressedIndex.has_value() && m_selectionManager->isSelected(m_pressedIndex.value());
|
const bool pressedItemAlreadySelected = m_pressedIndex.has_value() && m_selectionManager->isSelected(m_pressedIndex.value());
|
||||||
const bool clearSelection = m_selectionBehavior == SingleSelection ||
|
const bool clearSelection = m_selectionBehavior == SingleSelection ||
|
||||||
(!shiftOrControlPressed && !pressedItemAlreadySelected);
|
(!shiftOrControlPressed && !pressedItemAlreadySelected);
|
||||||
|
|
||||||
|
|
||||||
|
// When this method returns false, a rubberBand selection is created using KItemListController::startRubberBand via the caller.
|
||||||
if (clearSelection) {
|
if (clearSelection) {
|
||||||
|
const int selectedItemsCount = m_selectionManager->selectedItems().count();
|
||||||
m_selectionManager->clearSelection();
|
m_selectionManager->clearSelection();
|
||||||
|
// clear and bail when we got an existing multi-selection
|
||||||
|
if (selectedItemsCount > 1 && m_pressedIndex.has_value()) {
|
||||||
|
const auto row = m_view->m_visibleItems.value(m_pressedIndex.value());
|
||||||
|
const auto mappedPos = row->mapFromItem(m_view, pos);
|
||||||
|
if (pressedItemAlreadySelected || row->iconRect().contains(mappedPos) || row->textRect().contains(mappedPos)) {
|
||||||
|
// we are indeed inside the text/icon rect, keep m_pressedIndex what it is
|
||||||
|
// and short-circuit for single-click activation (it will then propagate to onRelease and activate the item)
|
||||||
|
// or we just keep going for double-click activation
|
||||||
|
if (m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced) {
|
||||||
|
return true; // event handled, don't create rubber band
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we're not inside the text/icon rect, as we've already cleared the selection
|
||||||
|
// we can just stop here and make sure handlers down the line (i.e. onRelease) don't activate
|
||||||
|
m_pressedIndex.reset();
|
||||||
|
// we don't stop event propagation and proceed to create a rubber band and let onRelease
|
||||||
|
// decide (based on m_pressedIndex) whether we're in a drag (drag => new rubber band, click => don't select the item)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (pressedItemAlreadySelected && !shiftOrControlPressed && (buttons & Qt::LeftButton)) {
|
} else if (pressedItemAlreadySelected && !shiftOrControlPressed && (buttons & Qt::LeftButton)) {
|
||||||
// The user might want to start dragging multiple items, but if he clicks the item
|
// The user might want to start dragging multiple items, but if he clicks the item
|
||||||
// in order to trigger it instead, the other selected items must be deselected.
|
// in order to trigger it instead, the other selected items must be deselected.
|
||||||
|
@ -1479,7 +1550,14 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
|
||||||
m_selectionManager->endAnchoredSelection();
|
m_selectionManager->endAnchoredSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttons & Qt::RightButton) {
|
if (rightClick) {
|
||||||
|
|
||||||
|
// Do header hit check and short circuit before commencing any state changing effects
|
||||||
|
if (m_view->headerBoundaries().contains(pos)) {
|
||||||
|
Q_EMIT headerContextMenuRequested(screenPos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Stop rubber band from persisting after right-clicks
|
// Stop rubber band from persisting after right-clicks
|
||||||
KItemListRubberBand* rubberBand = m_view->rubberBand();
|
KItemListRubberBand* rubberBand = m_view->rubberBand();
|
||||||
if (rubberBand->isActive()) {
|
if (rubberBand->isActive()) {
|
||||||
|
@ -1491,6 +1569,17 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
|
||||||
|
|
||||||
if (m_pressedIndex.has_value()) {
|
if (m_pressedIndex.has_value()) {
|
||||||
m_selectionManager->setCurrentItem(m_pressedIndex.value());
|
m_selectionManager->setCurrentItem(m_pressedIndex.value());
|
||||||
|
const auto row = m_view->m_visibleItems.value(m_pressedIndex.value()); // anything outside of row.contains() will be the empty region of the row rect
|
||||||
|
const bool hitTargetIsRowEmptyRegion = !row->contains(row->mapFromItem(m_view, pos));
|
||||||
|
// again, when this method returns false, a rubberBand selection is created as the event is not consumed;
|
||||||
|
// createRubberBand here tells us whether to return true or false.
|
||||||
|
bool createRubberBand = (hitTargetIsRowEmptyRegion && m_selectionManager->selectedItems().isEmpty());
|
||||||
|
|
||||||
|
if (rightClick && hitTargetIsRowEmptyRegion) {
|
||||||
|
// we got a right click outside the text rect, default to action on the current url and not the pressed item
|
||||||
|
Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (m_selectionBehavior) {
|
switch (m_selectionBehavior) {
|
||||||
case NoSelection:
|
case NoSelection:
|
||||||
|
@ -1504,6 +1593,7 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
|
||||||
if (controlPressed && !shiftPressed) {
|
if (controlPressed && !shiftPressed) {
|
||||||
m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Toggle);
|
m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Toggle);
|
||||||
m_selectionManager->beginAnchoredSelection(m_pressedIndex.value());
|
m_selectionManager->beginAnchoredSelection(m_pressedIndex.value());
|
||||||
|
createRubberBand = false; // multi selection, don't propagate any further
|
||||||
} else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) {
|
} else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) {
|
||||||
// Select the pressed item and start a new anchored selection
|
// Select the pressed item and start a new anchored selection
|
||||||
m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Select);
|
m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Select);
|
||||||
|
@ -1516,20 +1606,16 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttons & Qt::RightButton) {
|
if (rightClick) {
|
||||||
Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
|
Q_EMIT itemContextMenuRequested(m_pressedIndex.value(), screenPos);
|
||||||
}
|
}
|
||||||
|
return !createRubberBand;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttons & Qt::RightButton) {
|
if (rightClick) {
|
||||||
const QRectF headerBounds = m_view->headerBoundaries();
|
// header right click handling would have been done before this so just normal context
|
||||||
if (headerBounds.contains(pos)) {
|
// menu here is fine
|
||||||
Q_EMIT headerContextMenuRequested(screenPos);
|
|
||||||
} else {
|
|
||||||
Q_EMIT viewContextMenuRequested(screenPos);
|
Q_EMIT viewContextMenuRequested(screenPos);
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1554,15 +1640,34 @@ bool KItemListController::onRelease(const QPointF& pos, const Qt::KeyboardModifi
|
||||||
const bool shiftOrControlPressed = modifiers & Qt::ShiftModifier ||
|
const bool shiftOrControlPressed = modifiers & Qt::ShiftModifier ||
|
||||||
controlPressed;
|
controlPressed;
|
||||||
|
|
||||||
|
const std::optional<int> index = m_view->itemAt(pos);
|
||||||
|
|
||||||
KItemListRubberBand* rubberBand = m_view->rubberBand();
|
KItemListRubberBand* rubberBand = m_view->rubberBand();
|
||||||
|
bool rubberBandRelease = false;
|
||||||
if (rubberBand->isActive()) {
|
if (rubberBand->isActive()) {
|
||||||
disconnect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged);
|
disconnect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged);
|
||||||
rubberBand->setActive(false);
|
rubberBand->setActive(false);
|
||||||
m_oldSelection.clear();
|
m_oldSelection.clear();
|
||||||
m_view->setAutoScroll(false);
|
m_view->setAutoScroll(false);
|
||||||
|
rubberBandRelease = true;
|
||||||
|
// We check for actual rubber band drag here: if delta between start and end is less than drag threshold,
|
||||||
|
// then we have a single click on one of the rows
|
||||||
|
if ((rubberBand->endPosition() - rubberBand->startPosition()).manhattanLength() < QApplication::startDragDistance()) {
|
||||||
|
rubberBandRelease = false; // since we're only selecting, unmark rubber band release flag
|
||||||
|
// m_pressedIndex will have no value if we came from a multi-selection clearing onPress
|
||||||
|
// in that case, we don't select anything
|
||||||
|
if (index.has_value() && m_pressedIndex.has_value()) {
|
||||||
|
if (controlPressed && m_selectionBehavior == MultiSelection) {
|
||||||
|
m_selectionManager->setSelected(m_pressedIndex.value(), 1, KItemListSelectionManager::Toggle);
|
||||||
|
} else {
|
||||||
|
m_selectionManager->setSelected(index.value());
|
||||||
|
}
|
||||||
|
if (!m_selectionManager->isAnchoredSelectionActive()) {
|
||||||
|
m_selectionManager->beginAnchoredSelection(index.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::optional<int> index = m_view->itemAt(pos);
|
|
||||||
|
|
||||||
if (index.has_value() && index == m_pressedIndex) {
|
if (index.has_value() && index == m_pressedIndex) {
|
||||||
// The release event is done above the same item as the press event
|
// The release event is done above the same item as the press event
|
||||||
|
@ -1587,11 +1692,13 @@ bool KItemListController::onRelease(const QPointF& pos, const Qt::KeyboardModifi
|
||||||
// The mouse click should only update the selection, not trigger the item, except when
|
// The mouse click should only update the selection, not trigger the item, except when
|
||||||
// we are in single selection mode
|
// we are in single selection mode
|
||||||
emitItemActivated = false;
|
emitItemActivated = false;
|
||||||
} else if (!(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced)) {
|
|
||||||
if (touch) {
|
|
||||||
emitItemActivated = true;
|
|
||||||
} else {
|
} else {
|
||||||
emitItemActivated = false;
|
const bool singleClickActivation = m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced;
|
||||||
|
if (!singleClickActivation) {
|
||||||
|
emitItemActivated = touch;
|
||||||
|
} else {
|
||||||
|
// activate on single click only if we didn't come from a rubber band release
|
||||||
|
emitItemActivated = !rubberBandRelease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (emitItemActivated) {
|
if (emitItemActivated) {
|
||||||
|
|
|
@ -61,6 +61,20 @@ qreal KItemListHeader::preferredColumnWidth(const QByteArray& role) const
|
||||||
return m_headerWidget->preferredColumnWidth(role);
|
return m_headerWidget->preferredColumnWidth(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KItemListHeader::setLeadingPadding(qreal width){
|
||||||
|
if (m_headerWidget->leadingPadding() != width) {
|
||||||
|
m_headerWidget->setLeadingPadding(width);
|
||||||
|
if (m_headerWidget->automaticColumnResizing()) {
|
||||||
|
m_view->applyAutomaticColumnWidths();
|
||||||
|
}
|
||||||
|
m_view->doLayout(KItemListView::NoAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal KItemListHeader::leadingPadding() const{
|
||||||
|
return m_headerWidget->leadingPadding();
|
||||||
|
}
|
||||||
|
|
||||||
KItemListHeader::KItemListHeader(KItemListView* listView) :
|
KItemListHeader::KItemListHeader(KItemListView* listView) :
|
||||||
QObject(listView),
|
QObject(listView),
|
||||||
m_view(listView)
|
m_view(listView)
|
||||||
|
@ -72,5 +86,7 @@ KItemListHeader::KItemListHeader(KItemListView* listView) :
|
||||||
this, &KItemListHeader::columnWidthChanged);
|
this, &KItemListHeader::columnWidthChanged);
|
||||||
connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChangeFinished,
|
connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChangeFinished,
|
||||||
this, &KItemListHeader::columnWidthChangeFinished);
|
this, &KItemListHeader::columnWidthChangeFinished);
|
||||||
|
connect(m_headerWidget, &KItemListHeaderWidget::leadingPaddingChanged,
|
||||||
|
this, &KItemListHeader::leadingPaddingChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,16 @@ public:
|
||||||
*/
|
*/
|
||||||
qreal preferredColumnWidth(const QByteArray& role) const;
|
qreal preferredColumnWidth(const QByteArray& role) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the width of the column *before* the first column.
|
||||||
|
* This is intended to facilitate an empty region for deselection in the main viewport.
|
||||||
|
*/
|
||||||
|
void setLeadingPadding(qreal width);
|
||||||
|
qreal leadingPadding() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
void leadingPaddingChanged(qreal width);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is emitted if the width of a column has been adjusted by the user with the mouse
|
* 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).
|
* (no signal is emitted if KItemListHeader::setColumnWidth() is invoked).
|
||||||
|
|
|
@ -397,7 +397,7 @@ std::optional<int> KItemListView::itemAt(const QPointF& pos) const
|
||||||
|
|
||||||
const KItemListWidget* widget = it.value();
|
const KItemListWidget* widget = it.value();
|
||||||
const QPointF mappedPos = widget->mapFromItem(this, pos);
|
const QPointF mappedPos = widget->mapFromItem(this, pos);
|
||||||
if (widget->contains(mappedPos)) {
|
if (widget->contains(mappedPos) || widget->selectionRect().contains(mappedPos)) {
|
||||||
return it.key();
|
return it.key();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -477,6 +477,32 @@ bool KItemListView::supportsItemExpanding() const
|
||||||
return m_supportsItemExpanding;
|
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
|
QRectF KItemListView::itemRect(int index) const
|
||||||
{
|
{
|
||||||
return m_layouter->itemRect(index);
|
return m_layouter->itemRect(index);
|
||||||
|
@ -581,6 +607,8 @@ void KItemListView::setHeaderVisible(bool visible)
|
||||||
|
|
||||||
connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged,
|
connect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged,
|
||||||
this, &KItemListView::slotHeaderColumnWidthChanged);
|
this, &KItemListView::slotHeaderColumnWidthChanged);
|
||||||
|
connect(m_headerWidget, &KItemListHeaderWidget::leadingPaddingChanged,
|
||||||
|
this, &KItemListView::slotLeadingPaddingChanged);
|
||||||
connect(m_headerWidget, &KItemListHeaderWidget::columnMoved,
|
connect(m_headerWidget, &KItemListHeaderWidget::columnMoved,
|
||||||
this, &KItemListView::slotHeaderColumnMoved);
|
this, &KItemListView::slotHeaderColumnMoved);
|
||||||
connect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged,
|
connect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged,
|
||||||
|
@ -593,6 +621,8 @@ void KItemListView::setHeaderVisible(bool visible)
|
||||||
} else if (!visible && m_headerWidget->isVisible()) {
|
} else if (!visible && m_headerWidget->isVisible()) {
|
||||||
disconnect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged,
|
disconnect(m_headerWidget, &KItemListHeaderWidget::columnWidthChanged,
|
||||||
this, &KItemListView::slotHeaderColumnWidthChanged);
|
this, &KItemListView::slotHeaderColumnWidthChanged);
|
||||||
|
disconnect(m_headerWidget, &KItemListHeaderWidget::leadingPaddingChanged,
|
||||||
|
this, &KItemListView::slotLeadingPaddingChanged);
|
||||||
disconnect(m_headerWidget, &KItemListHeaderWidget::columnMoved,
|
disconnect(m_headerWidget, &KItemListHeaderWidget::columnMoved,
|
||||||
this, &KItemListView::slotHeaderColumnMoved);
|
this, &KItemListView::slotHeaderColumnMoved);
|
||||||
disconnect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged,
|
disconnect(m_headerWidget, &KItemListHeaderWidget::sortOrderChanged,
|
||||||
|
@ -753,7 +783,7 @@ void KItemListView::setItemSize(const QSizeF& size)
|
||||||
size,
|
size,
|
||||||
m_layouter->itemMargin());
|
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()) ||
|
||||||
(!m_itemSize.isEmpty() && size.isEmpty()));
|
(!m_itemSize.isEmpty() && size.isEmpty()));
|
||||||
|
|
||||||
|
@ -929,6 +959,11 @@ void KItemListView::onStyleOptionChanged(const KItemListStyleOption& current, co
|
||||||
Q_UNUSED(previous)
|
Q_UNUSED(previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KItemListView::onHighlightEntireRowChanged(bool highlightEntireRow)
|
||||||
|
{
|
||||||
|
Q_UNUSED(highlightEntireRow)
|
||||||
|
}
|
||||||
|
|
||||||
void KItemListView::onSupportsItemExpandingChanged(bool supportsExpanding)
|
void KItemListView::onSupportsItemExpandingChanged(bool supportsExpanding)
|
||||||
{
|
{
|
||||||
Q_UNUSED(supportsExpanding)
|
Q_UNUSED(supportsExpanding)
|
||||||
|
@ -1521,6 +1556,16 @@ void KItemListView::slotHeaderColumnWidthChanged(const QByteArray& role,
|
||||||
doLayout(NoAnimation);
|
doLayout(NoAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KItemListView::slotLeadingPaddingChanged(qreal width)
|
||||||
|
{
|
||||||
|
Q_UNUSED(width)
|
||||||
|
if (m_headerWidget->automaticColumnResizing()) {
|
||||||
|
applyAutomaticColumnWidths();
|
||||||
|
}
|
||||||
|
applyColumnWidthsFromHeader();
|
||||||
|
doLayout(NoAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
void KItemListView::slotHeaderColumnMoved(const QByteArray& role,
|
void KItemListView::slotHeaderColumnMoved(const QByteArray& role,
|
||||||
int currentIndex,
|
int currentIndex,
|
||||||
int previousIndex)
|
int previousIndex)
|
||||||
|
@ -2225,7 +2270,7 @@ void KItemListView::updateAlternateBackgroundForWidget(KItemListWidget* widget)
|
||||||
|
|
||||||
bool KItemListView::useAlternateBackgrounds() const
|
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
|
QHash<QByteArray, qreal> KItemListView::preferredColumnWidths(const KItemRangeList& itemRanges) const
|
||||||
|
@ -2283,7 +2328,7 @@ QHash<QByteArray, qreal> KItemListView::preferredColumnWidths(const KItemRangeLi
|
||||||
void KItemListView::applyColumnWidthsFromHeader()
|
void KItemListView::applyColumnWidthsFromHeader()
|
||||||
{
|
{
|
||||||
// Apply the new size to the layouter
|
// 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),
|
const QSizeF dynamicItemSize(qMax(size().width(), requiredWidth),
|
||||||
m_itemSize.height());
|
m_itemSize.height());
|
||||||
m_layouter->setItemSize(dynamicItemSize);
|
m_layouter->setItemSize(dynamicItemSize);
|
||||||
|
@ -2301,6 +2346,7 @@ void KItemListView::updateWidgetColumnWidths(KItemListWidget* widget)
|
||||||
for (const QByteArray& role : qAsConst(m_visibleRoles)) {
|
for (const QByteArray& role : qAsConst(m_visibleRoles)) {
|
||||||
widget->setColumnWidth(role, m_headerWidget->columnWidth(role));
|
widget->setColumnWidth(role, m_headerWidget->columnWidth(role));
|
||||||
}
|
}
|
||||||
|
widget->setLeadingPadding(m_headerWidget->leadingPadding());
|
||||||
}
|
}
|
||||||
|
|
||||||
void KItemListView::updatePreferredColumnWidths(const KItemRangeList& itemRanges)
|
void KItemListView::updatePreferredColumnWidths(const KItemRangeList& itemRanges)
|
||||||
|
@ -2378,7 +2424,7 @@ void KItemListView::applyAutomaticColumnWidths()
|
||||||
qreal firstColumnWidth = m_headerWidget->columnWidth(firstRole);
|
qreal firstColumnWidth = m_headerWidget->columnWidth(firstRole);
|
||||||
QSizeF dynamicItemSize = m_itemSize;
|
QSizeF dynamicItemSize = m_itemSize;
|
||||||
|
|
||||||
qreal requiredWidth = columnWidthsSum();
|
qreal requiredWidth = columnWidthsSum() + m_headerWidget->leadingPadding();
|
||||||
const qreal availableWidth = size().width();
|
const qreal availableWidth = size().width();
|
||||||
if (requiredWidth < availableWidth) {
|
if (requiredWidth < availableWidth) {
|
||||||
// Stretch the first column to use the whole remaining width
|
// Stretch the first column to use the whole remaining width
|
||||||
|
|
|
@ -205,6 +205,12 @@ public:
|
||||||
void setSupportsItemExpanding(bool supportsExpanding);
|
void setSupportsItemExpanding(bool supportsExpanding);
|
||||||
bool supportsItemExpanding() const;
|
bool supportsItemExpanding() const;
|
||||||
|
|
||||||
|
void setHighlightEntireRow(bool highlightEntireRow);
|
||||||
|
bool highlightEntireRow() const;
|
||||||
|
|
||||||
|
void setAlternateBackgrounds(bool alternate);
|
||||||
|
bool alternateBackgrounds() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The rectangle of the item relative to the top/left of
|
* @return The rectangle of the item relative to the top/left of
|
||||||
* the currently visible area (see KItemListView::offset()).
|
* the currently visible area (see KItemListView::offset()).
|
||||||
|
@ -374,6 +380,7 @@ protected:
|
||||||
virtual void onScrollOffsetChanged(qreal current, qreal previous);
|
virtual void onScrollOffsetChanged(qreal current, qreal previous);
|
||||||
virtual void onVisibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous);
|
virtual void onVisibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous);
|
||||||
virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
|
virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
|
||||||
|
virtual void onHighlightEntireRowChanged(bool highlightEntireRow);
|
||||||
virtual void onSupportsItemExpandingChanged(bool supportsExpanding);
|
virtual void onSupportsItemExpandingChanged(bool supportsExpanding);
|
||||||
|
|
||||||
virtual void onTransactionBegin();
|
virtual void onTransactionBegin();
|
||||||
|
@ -426,6 +433,8 @@ private Q_SLOTS:
|
||||||
qreal currentWidth,
|
qreal currentWidth,
|
||||||
qreal previousWidth);
|
qreal previousWidth);
|
||||||
|
|
||||||
|
void slotLeadingPaddingChanged(qreal width);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is invoked if a column 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.
|
* the moved role to the view.
|
||||||
|
@ -707,6 +716,8 @@ private:
|
||||||
private:
|
private:
|
||||||
bool m_enabledSelectionToggles;
|
bool m_enabledSelectionToggles;
|
||||||
bool m_grouped;
|
bool m_grouped;
|
||||||
|
bool m_highlightEntireRow;
|
||||||
|
bool m_alternateBackgrounds;
|
||||||
bool m_supportsItemExpanding;
|
bool m_supportsItemExpanding;
|
||||||
bool m_editingRole;
|
bool m_editingRole;
|
||||||
int m_activeTransactions; // Counter for beginTransaction()/endTransaction()
|
int m_activeTransactions; // Counter for beginTransaction()/endTransaction()
|
||||||
|
|
|
@ -34,6 +34,7 @@ KItemListWidget::KItemListWidget(KItemListWidgetInformant* informant, QGraphicsI
|
||||||
m_selected(false),
|
m_selected(false),
|
||||||
m_current(false),
|
m_current(false),
|
||||||
m_hovered(false),
|
m_hovered(false),
|
||||||
|
m_expansionAreaHovered(false),
|
||||||
m_alternateBackground(false),
|
m_alternateBackground(false),
|
||||||
m_enabledSelectionToggle(false),
|
m_enabledSelectionToggle(false),
|
||||||
m_data(),
|
m_data(),
|
||||||
|
@ -180,6 +181,18 @@ qreal KItemListWidget::columnWidth(const QByteArray& role) const
|
||||||
return m_columnWidths.value(role);
|
return m_columnWidths.value(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal KItemListWidget::leadingPadding() const {
|
||||||
|
return m_leadingPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KItemListWidget::setLeadingPadding(qreal width) {
|
||||||
|
if (m_leadingPadding != width){
|
||||||
|
m_leadingPadding = width;
|
||||||
|
leadingPaddingChanged(width);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void KItemListWidget::setStyleOption(const KItemListStyleOption& option)
|
void KItemListWidget::setStyleOption(const KItemListStyleOption& option)
|
||||||
{
|
{
|
||||||
if (m_styleOption == option) {
|
if (m_styleOption == option) {
|
||||||
|
@ -280,6 +293,20 @@ bool KItemListWidget::isHovered() const
|
||||||
return m_hovered;
|
return m_hovered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KItemListWidget::setExpansionAreaHovered(bool hovered)
|
||||||
|
{
|
||||||
|
if (hovered == m_expansionAreaHovered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_expansionAreaHovered = hovered;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KItemListWidget::expansionAreaHovered() const
|
||||||
|
{
|
||||||
|
return m_expansionAreaHovered;
|
||||||
|
}
|
||||||
|
|
||||||
void KItemListWidget::setHoverPosition(const QPointF& pos)
|
void KItemListWidget::setHoverPosition(const QPointF& pos)
|
||||||
{
|
{
|
||||||
if (m_selectionToggle) {
|
if (m_selectionToggle) {
|
||||||
|
@ -416,6 +443,11 @@ void KItemListWidget::columnWidthChanged(const QByteArray& role,
|
||||||
Q_UNUSED(previous)
|
Q_UNUSED(previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KItemListWidget::leadingPaddingChanged(qreal width)
|
||||||
|
{
|
||||||
|
Q_UNUSED(width)
|
||||||
|
}
|
||||||
|
|
||||||
void KItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
|
void KItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
|
||||||
const KItemListStyleOption& previous)
|
const KItemListStyleOption& previous)
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,6 +80,9 @@ public:
|
||||||
void setColumnWidth(const QByteArray& role, qreal width);
|
void setColumnWidth(const QByteArray& role, qreal width);
|
||||||
qreal columnWidth(const QByteArray& role) const;
|
qreal columnWidth(const QByteArray& role) const;
|
||||||
|
|
||||||
|
void setLeadingPadding(qreal width);
|
||||||
|
qreal leadingPadding() const;
|
||||||
|
|
||||||
void setStyleOption(const KItemListStyleOption& option);
|
void setStyleOption(const KItemListStyleOption& option);
|
||||||
const KItemListStyleOption& styleOption() const;
|
const KItemListStyleOption& styleOption() const;
|
||||||
|
|
||||||
|
@ -94,6 +97,9 @@ public:
|
||||||
void setHovered(bool hovered);
|
void setHovered(bool hovered);
|
||||||
bool isHovered() const;
|
bool isHovered() const;
|
||||||
|
|
||||||
|
void setExpansionAreaHovered(bool hover);
|
||||||
|
bool expansionAreaHovered() const;
|
||||||
|
|
||||||
void setHoverPosition(const QPointF& pos);
|
void setHoverPosition(const QPointF& pos);
|
||||||
|
|
||||||
void setAlternateBackground(bool enable);
|
void setAlternateBackground(bool enable);
|
||||||
|
@ -182,6 +188,7 @@ protected:
|
||||||
virtual void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>());
|
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 visibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous);
|
||||||
virtual void columnWidthChanged(const QByteArray& role, qreal current, qreal previous);
|
virtual void columnWidthChanged(const QByteArray& role, qreal current, qreal previous);
|
||||||
|
virtual void leadingPaddingChanged(qreal width);
|
||||||
virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
|
virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
|
||||||
virtual void currentChanged(bool current);
|
virtual void currentChanged(bool current);
|
||||||
virtual void selectedChanged(bool selected);
|
virtual void selectedChanged(bool selected);
|
||||||
|
@ -190,6 +197,7 @@ protected:
|
||||||
virtual void siblingsInformationChanged(const QBitArray& current, const QBitArray& previous);
|
virtual void siblingsInformationChanged(const QBitArray& current, const QBitArray& previous);
|
||||||
virtual void editedRoleChanged(const QByteArray& current, const QByteArray& previous);
|
virtual void editedRoleChanged(const QByteArray& current, const QByteArray& previous);
|
||||||
void resizeEvent(QGraphicsSceneResizeEvent* event) override;
|
void resizeEvent(QGraphicsSceneResizeEvent* event) override;
|
||||||
|
void clearHoverCache();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the user starts hovering this item.
|
* Called when the user starts hovering this item.
|
||||||
|
@ -225,7 +233,6 @@ private Q_SLOTS:
|
||||||
private:
|
private:
|
||||||
void initializeSelectionToggle();
|
void initializeSelectionToggle();
|
||||||
void setHoverOpacity(qreal opacity);
|
void setHoverOpacity(qreal opacity);
|
||||||
void clearHoverCache();
|
|
||||||
void drawItemStyleOption(QPainter* painter, QWidget* widget, QStyle::State styleState);
|
void drawItemStyleOption(QPainter* painter, QWidget* widget, QStyle::State styleState);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -236,11 +243,13 @@ private:
|
||||||
bool m_selected;
|
bool m_selected;
|
||||||
bool m_current;
|
bool m_current;
|
||||||
bool m_hovered;
|
bool m_hovered;
|
||||||
|
bool m_expansionAreaHovered;
|
||||||
bool m_alternateBackground;
|
bool m_alternateBackground;
|
||||||
bool m_enabledSelectionToggle;
|
bool m_enabledSelectionToggle;
|
||||||
QHash<QByteArray, QVariant> m_data;
|
QHash<QByteArray, QVariant> m_data;
|
||||||
QList<QByteArray> m_visibleRoles;
|
QList<QByteArray> m_visibleRoles;
|
||||||
QHash<QByteArray, qreal> m_columnWidths;
|
QHash<QByteArray, qreal> m_columnWidths;
|
||||||
|
qreal m_leadingPadding;
|
||||||
KItemListStyleOption m_styleOption;
|
KItemListStyleOption m_styleOption;
|
||||||
QBitArray m_siblingsInfo;
|
QBitArray m_siblingsInfo;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ KStandardItemListView::KStandardItemListView(QGraphicsWidget* parent) :
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
setScrollOrientation(Qt::Vertical);
|
setScrollOrientation(Qt::Vertical);
|
||||||
setVisibleRoles({"text"});
|
setVisibleRoles({"text"});
|
||||||
|
setAlternateBackgrounds(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
KStandardItemListView::~KStandardItemListView()
|
KStandardItemListView::~KStandardItemListView()
|
||||||
|
@ -34,6 +35,8 @@ void KStandardItemListView::setItemLayout(ItemLayout layout)
|
||||||
const ItemLayout previous = m_itemLayout;
|
const ItemLayout previous = m_itemLayout;
|
||||||
m_itemLayout = layout;
|
m_itemLayout = layout;
|
||||||
|
|
||||||
|
// keep the leading padding option unchanged here
|
||||||
|
setHighlightEntireRow(layout == DetailsLayout);
|
||||||
setSupportsItemExpanding(itemLayoutSupportsItemExpanding(layout));
|
setSupportsItemExpanding(itemLayoutSupportsItemExpanding(layout));
|
||||||
setScrollOrientation(layout == CompactLayout ? Qt::Horizontal : Qt::Vertical);
|
setScrollOrientation(layout == CompactLayout ? Qt::Horizontal : Qt::Vertical);
|
||||||
|
|
||||||
|
@ -69,6 +72,7 @@ void KStandardItemListView::initializeItemListWidget(KItemListWidget* item)
|
||||||
default: Q_ASSERT(false); break;
|
default: Q_ASSERT(false); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
standardItemListWidget->setHighlightEntireRow(highlightEntireRow());
|
||||||
standardItemListWidget->setSupportsItemExpanding(supportsItemExpanding());
|
standardItemListWidget->setSupportsItemExpanding(supportsItemExpanding());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -264,6 +264,7 @@ KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* infor
|
||||||
m_pixmapPos(),
|
m_pixmapPos(),
|
||||||
m_pixmap(),
|
m_pixmap(),
|
||||||
m_scaledPixmapSize(),
|
m_scaledPixmapSize(),
|
||||||
|
m_columnWidthSum(),
|
||||||
m_iconRect(),
|
m_iconRect(),
|
||||||
m_hoverPixmap(),
|
m_hoverPixmap(),
|
||||||
m_textRect(),
|
m_textRect(),
|
||||||
|
@ -307,6 +308,18 @@ KStandardItemListWidget::Layout KStandardItemListWidget::layout() const
|
||||||
return m_layout;
|
return m_layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KStandardItemListWidget::setHighlightEntireRow(bool highlightEntireRow) {
|
||||||
|
if (m_highlightEntireRow != highlightEntireRow) {
|
||||||
|
m_highlightEntireRow = highlightEntireRow;
|
||||||
|
m_dirtyLayout = true;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KStandardItemListWidget::highlightEntireRow() const {
|
||||||
|
return m_highlightEntireRow;
|
||||||
|
}
|
||||||
|
|
||||||
void KStandardItemListWidget::setSupportsItemExpanding(bool supportsItemExpanding)
|
void KStandardItemListWidget::setSupportsItemExpanding(bool supportsItemExpanding)
|
||||||
{
|
{
|
||||||
if (m_supportsItemExpanding != supportsItemExpanding) {
|
if (m_supportsItemExpanding != supportsItemExpanding) {
|
||||||
|
@ -508,7 +521,11 @@ QRectF KStandardItemListWidget::selectionRect() const
|
||||||
case DetailsLayout: {
|
case DetailsLayout: {
|
||||||
const int padding = styleOption().padding;
|
const int padding = styleOption().padding;
|
||||||
QRectF adjustedIconRect = iconRect().adjusted(-padding, -padding, padding, padding);
|
QRectF adjustedIconRect = iconRect().adjusted(-padding, -padding, padding, padding);
|
||||||
return adjustedIconRect | m_textRect;
|
QRectF result = adjustedIconRect | m_textRect;
|
||||||
|
if (m_highlightEntireRow) {
|
||||||
|
result.setRight(m_columnWidthSum + leadingPadding());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -725,6 +742,11 @@ void KStandardItemListWidget::columnWidthChanged(const QByteArray& role,
|
||||||
m_dirtyLayout = true;
|
m_dirtyLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KStandardItemListWidget::leadingPaddingChanged(qreal padding) {
|
||||||
|
Q_UNUSED(padding)
|
||||||
|
m_dirtyLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
void KStandardItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
|
void KStandardItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
|
||||||
const KItemListStyleOption& previous)
|
const KItemListStyleOption& previous)
|
||||||
{
|
{
|
||||||
|
@ -917,10 +939,13 @@ void KStandardItemListWidget::triggerCacheRefreshing()
|
||||||
m_isHidden = isHidden();
|
m_isHidden = isHidden();
|
||||||
m_customizedFont = customizedFont(styleOption().font);
|
m_customizedFont = customizedFont(styleOption().font);
|
||||||
m_customizedFontMetrics = QFontMetrics(m_customizedFont);
|
m_customizedFontMetrics = QFontMetrics(m_customizedFont);
|
||||||
|
m_columnWidthSum = std::accumulate(m_sortedVisibleRoles.begin(), m_sortedVisibleRoles.end(),
|
||||||
|
qreal(), [this](qreal sum, const auto &role){ return sum + columnWidth(role); });
|
||||||
|
|
||||||
updateExpansionArea();
|
updateExpansionArea();
|
||||||
updateTextsCache();
|
updateTextsCache();
|
||||||
updatePixmapCache();
|
updatePixmapCache();
|
||||||
|
clearHoverCache();
|
||||||
|
|
||||||
m_dirtyLayout = false;
|
m_dirtyLayout = false;
|
||||||
m_dirtyContent = false;
|
m_dirtyContent = false;
|
||||||
|
@ -938,7 +963,8 @@ void KStandardItemListWidget::updateExpansionArea()
|
||||||
const qreal inc = (widgetHeight - option.iconSize) / 2;
|
const qreal inc = (widgetHeight - option.iconSize) / 2;
|
||||||
const qreal x = expandedParentsCount * widgetHeight + inc;
|
const qreal x = expandedParentsCount * widgetHeight + inc;
|
||||||
const qreal y = inc;
|
const qreal y = inc;
|
||||||
m_expansionArea = QRectF(x, y, option.iconSize, option.iconSize);
|
const qreal xPadding = m_highlightEntireRow ? leadingPadding() : 0;
|
||||||
|
m_expansionArea = QRectF(xPadding + x, y, option.iconSize, option.iconSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1375,7 +1401,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache()
|
||||||
if (m_supportsItemExpanding) {
|
if (m_supportsItemExpanding) {
|
||||||
firstColumnInc += (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2;
|
firstColumnInc += (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2;
|
||||||
} else {
|
} else {
|
||||||
firstColumnInc += option.padding;
|
firstColumnInc += option.padding + leadingPadding();
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal x = firstColumnInc;
|
qreal x = firstColumnInc;
|
||||||
|
@ -1391,7 +1417,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache()
|
||||||
|
|
||||||
const bool isTextRole = (role == "text");
|
const bool isTextRole = (role == "text");
|
||||||
if (isTextRole) {
|
if (isTextRole) {
|
||||||
availableTextWidth -= firstColumnInc;
|
availableTextWidth -= firstColumnInc - leadingPadding();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requiredWidth > availableTextWidth) {
|
if (requiredWidth > availableTextWidth) {
|
||||||
|
@ -1413,7 +1439,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache()
|
||||||
|
|
||||||
// The column after the name should always be aligned on the same x-position independent
|
// The column after the name should always be aligned on the same x-position independent
|
||||||
// from the expansion-level shown in the name column
|
// from the expansion-level shown in the name column
|
||||||
x -= firstColumnInc;
|
x -= firstColumnInc - leadingPadding();
|
||||||
} else if (isRoleRightAligned(role)) {
|
} else if (isRoleRightAligned(role)) {
|
||||||
textInfo->pos.rx() += roleWidth - requiredWidth - columnWidthInc;
|
textInfo->pos.rx() += roleWidth - requiredWidth - columnWidthInc;
|
||||||
}
|
}
|
||||||
|
@ -1425,8 +1451,11 @@ void KStandardItemListWidget::updateAdditionalInfoTextColor()
|
||||||
QColor c1;
|
QColor c1;
|
||||||
if (m_customTextColor.isValid()) {
|
if (m_customTextColor.isValid()) {
|
||||||
c1 = m_customTextColor;
|
c1 = m_customTextColor;
|
||||||
} else if (isSelected() && m_layout != DetailsLayout) {
|
} else if (isSelected()) {
|
||||||
c1 = styleOption().palette.highlightedText().color();
|
// The detail text colour needs to match the main text (HighlightedText) for the same level
|
||||||
|
// of readability. We short circuit early here to avoid interpolating with another colour.
|
||||||
|
m_additionalInfoTextColor = styleOption().palette.color(QPalette::HighlightedText);
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
c1 = styleOption().palette.text().color();
|
c1 = styleOption().palette.text().color();
|
||||||
}
|
}
|
||||||
|
@ -1465,15 +1494,15 @@ void KStandardItemListWidget::drawSiblingsInformation(QPainter* painter)
|
||||||
const int x = (m_expansionArea.left() + m_expansionArea.right() - siblingSize) / 2;
|
const int x = (m_expansionArea.left() + m_expansionArea.right() - siblingSize) / 2;
|
||||||
QRect siblingRect(x, 0, siblingSize, siblingSize);
|
QRect siblingRect(x, 0, siblingSize, siblingSize);
|
||||||
|
|
||||||
QStyleOption option;
|
|
||||||
option.palette.setColor(QPalette::Text, option.palette.color(normalTextColorRole()));
|
|
||||||
bool isItemSibling = true;
|
bool isItemSibling = true;
|
||||||
|
|
||||||
const QBitArray siblings = siblingsInformation();
|
const QBitArray siblings = siblingsInformation();
|
||||||
|
QStyleOption option;
|
||||||
|
const auto normalColor = option.palette.color(normalTextColorRole());
|
||||||
|
const auto highlightColor = option.palette.color(expansionAreaHovered() ? QPalette::Highlight : normalTextColorRole());
|
||||||
for (int i = siblings.count() - 1; i >= 0; --i) {
|
for (int i = siblings.count() - 1; i >= 0; --i) {
|
||||||
option.rect = siblingRect;
|
option.rect = siblingRect;
|
||||||
option.state = siblings.at(i) ? QStyle::State_Sibling : QStyle::State_None;
|
option.state = siblings.at(i) ? QStyle::State_Sibling : QStyle::State_None;
|
||||||
|
|
||||||
if (isItemSibling) {
|
if (isItemSibling) {
|
||||||
option.state |= QStyle::State_Item;
|
option.state |= QStyle::State_Item;
|
||||||
if (m_isExpandable) {
|
if (m_isExpandable) {
|
||||||
|
@ -1482,7 +1511,10 @@ void KStandardItemListWidget::drawSiblingsInformation(QPainter* painter)
|
||||||
if (data().value("isExpanded").toBool()) {
|
if (data().value("isExpanded").toBool()) {
|
||||||
option.state |= QStyle::State_Open;
|
option.state |= QStyle::State_Open;
|
||||||
}
|
}
|
||||||
|
option.palette.setColor(QPalette::Text, highlightColor);
|
||||||
isItemSibling = false;
|
isItemSibling = false;
|
||||||
|
} else {
|
||||||
|
option.palette.setColor(QPalette::Text, normalColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter);
|
style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter);
|
||||||
|
|
|
@ -88,6 +88,9 @@ public:
|
||||||
void setLayout(Layout layout);
|
void setLayout(Layout layout);
|
||||||
Layout layout() const;
|
Layout layout() const;
|
||||||
|
|
||||||
|
void setHighlightEntireRow(bool highlightEntireRow);
|
||||||
|
bool highlightEntireRow() const;
|
||||||
|
|
||||||
void setSupportsItemExpanding(bool supportsItemExpanding);
|
void setSupportsItemExpanding(bool supportsItemExpanding);
|
||||||
bool supportsItemExpanding() const;
|
bool supportsItemExpanding() const;
|
||||||
|
|
||||||
|
@ -168,6 +171,7 @@ protected:
|
||||||
void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>()) override;
|
void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>()) override;
|
||||||
void visibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous) override;
|
void visibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous) override;
|
||||||
void columnWidthChanged(const QByteArray& role, qreal current, qreal previous) override;
|
void columnWidthChanged(const QByteArray& role, qreal current, qreal previous) override;
|
||||||
|
void leadingPaddingChanged(qreal width) override;
|
||||||
void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous) override;
|
void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous) override;
|
||||||
void hoveredChanged(bool hovered) override;
|
void hoveredChanged(bool hovered) override;
|
||||||
void selectedChanged(bool selected) override;
|
void selectedChanged(bool selected) override;
|
||||||
|
@ -241,6 +245,7 @@ private:
|
||||||
QFont m_customizedFont;
|
QFont m_customizedFont;
|
||||||
QFontMetrics m_customizedFontMetrics;
|
QFontMetrics m_customizedFontMetrics;
|
||||||
bool m_isExpandable;
|
bool m_isExpandable;
|
||||||
|
bool m_highlightEntireRow;
|
||||||
bool m_supportsItemExpanding;
|
bool m_supportsItemExpanding;
|
||||||
|
|
||||||
bool m_dirtyLayout;
|
bool m_dirtyLayout;
|
||||||
|
@ -252,6 +257,7 @@ private:
|
||||||
QPixmap m_pixmap;
|
QPixmap m_pixmap;
|
||||||
QSize m_scaledPixmapSize; //Size of the pixmap in device independent pixels
|
QSize m_scaledPixmapSize; //Size of the pixmap in device independent pixels
|
||||||
|
|
||||||
|
qreal m_columnWidthSum;
|
||||||
QRectF m_iconRect; // Cache for KItemListWidget::iconRect()
|
QRectF m_iconRect; // Cache for KItemListWidget::iconRect()
|
||||||
QPixmap m_hoverPixmap; // Cache for modified m_pixmap when hovering the item
|
QPixmap m_hoverPixmap; // Cache for modified m_pixmap when hovering the item
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget* parent) :
|
||||||
m_automaticColumnResizing(true),
|
m_automaticColumnResizing(true),
|
||||||
m_model(nullptr),
|
m_model(nullptr),
|
||||||
m_offset(0),
|
m_offset(0),
|
||||||
|
m_leadingPadding(0),
|
||||||
m_columns(),
|
m_columns(),
|
||||||
m_columnWidths(),
|
m_columnWidths(),
|
||||||
m_preferredColumnWidths(),
|
m_preferredColumnWidths(),
|
||||||
|
@ -134,6 +135,20 @@ qreal KItemListHeaderWidget::offset() const
|
||||||
return m_offset;
|
return m_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KItemListHeaderWidget::setLeadingPadding(qreal width)
|
||||||
|
{
|
||||||
|
if (m_leadingPadding != width) {
|
||||||
|
m_leadingPadding = width;
|
||||||
|
leadingPaddingChanged(width);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal KItemListHeaderWidget::leadingPadding() const
|
||||||
|
{
|
||||||
|
return m_leadingPadding;
|
||||||
|
}
|
||||||
|
|
||||||
qreal KItemListHeaderWidget::minimumColumnWidth() const
|
qreal KItemListHeaderWidget::minimumColumnWidth() const
|
||||||
{
|
{
|
||||||
QFontMetricsF fontMetrics(font());
|
QFontMetricsF fontMetrics(font());
|
||||||
|
@ -153,7 +168,7 @@ void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsI
|
||||||
painter->setFont(font());
|
painter->setFont(font());
|
||||||
painter->setPen(palette().text().color());
|
painter->setPen(palette().text().color());
|
||||||
|
|
||||||
qreal x = -m_offset;
|
qreal x = -m_offset + m_leadingPadding;
|
||||||
int orderIndex = 0;
|
int orderIndex = 0;
|
||||||
for (const QByteArray& role : qAsConst(m_columns)) {
|
for (const QByteArray& role : qAsConst(m_columns)) {
|
||||||
const qreal roleWidth = m_columnWidths.value(role);
|
const qreal roleWidth = m_columnWidths.value(role);
|
||||||
|
@ -172,10 +187,14 @@ void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsI
|
||||||
void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent* event)
|
void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent* event)
|
||||||
{
|
{
|
||||||
if (event->button() & Qt::LeftButton) {
|
if (event->button() & Qt::LeftButton) {
|
||||||
updatePressedRoleIndex(event->pos());
|
|
||||||
m_pressedMousePos = event->pos();
|
m_pressedMousePos = event->pos();
|
||||||
|
if (isAbovePaddingGrip(m_pressedMousePos, PaddingGrip::Leading)) {
|
||||||
|
m_roleOperation = ResizeLeadingColumnOperation;
|
||||||
|
} else {
|
||||||
|
updatePressedRoleIndex(event->pos());
|
||||||
m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ?
|
m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ?
|
||||||
ResizeRoleOperation : NoRoleOperation;
|
ResizeRoleOperation : NoRoleOperation;
|
||||||
|
}
|
||||||
event->accept();
|
event->accept();
|
||||||
} else {
|
} else {
|
||||||
event->ignore();
|
event->ignore();
|
||||||
|
@ -263,7 +282,7 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
|
||||||
} else {
|
} else {
|
||||||
m_movingRole.pixmap = createRolePixmap(roleIndex);
|
m_movingRole.pixmap = createRolePixmap(roleIndex);
|
||||||
|
|
||||||
qreal roleX = -m_offset;
|
qreal roleX = -m_offset + m_leadingPadding;
|
||||||
for (int i = 0; i < roleIndex; ++i) {
|
for (int i = 0; i < roleIndex; ++i) {
|
||||||
const QByteArray role = m_columns[i];
|
const QByteArray role = m_columns[i];
|
||||||
roleX += m_columnWidths.value(role);
|
roleX += m_columnWidths.value(role);
|
||||||
|
@ -291,6 +310,20 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ResizeLeadingColumnOperation: {
|
||||||
|
qreal currentWidth = m_leadingPadding;
|
||||||
|
currentWidth += event->pos().x() - event->lastPos().x();
|
||||||
|
currentWidth = qMax(0.0, currentWidth);
|
||||||
|
|
||||||
|
m_leadingPadding = currentWidth;
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
Q_EMIT leadingPaddingChanged(currentWidth);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MoveRoleOperation: {
|
case MoveRoleOperation: {
|
||||||
// TODO: It should be configurable whether moving the first role is allowed.
|
// 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
|
// In the context of Dolphin this is not required, however this should be
|
||||||
|
@ -355,7 +388,9 @@ void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
|
||||||
|
|
||||||
const QPointF& pos = event->pos();
|
const QPointF& pos = event->pos();
|
||||||
updateHoveredRoleIndex(pos);
|
updateHoveredRoleIndex(pos);
|
||||||
if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) {
|
if ((m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) ||
|
||||||
|
isAbovePaddingGrip(pos, PaddingGrip::Leading) ||
|
||||||
|
isAbovePaddingGrip(pos, PaddingGrip::Trailing)) {
|
||||||
setCursor(Qt::SplitHCursor);
|
setCursor(Qt::SplitHCursor);
|
||||||
} else {
|
} else {
|
||||||
unsetCursor();
|
unsetCursor();
|
||||||
|
@ -404,45 +439,47 @@ void KItemListHeaderWidget::paintRole(QPainter* painter,
|
||||||
QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
|
QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
|
||||||
}
|
}
|
||||||
option.rect = rect.toRect();
|
option.rect = rect.toRect();
|
||||||
|
|
||||||
bool paintBackgroundForEmptyArea = false;
|
|
||||||
|
|
||||||
if (m_columns.count() == 1) {
|
|
||||||
option.position = QStyleOptionHeader::OnlyOneSection;
|
|
||||||
} else if (orderIndex == 0) {
|
|
||||||
option.position = QStyleOptionHeader::Beginning;
|
|
||||||
} else if (orderIndex == m_columns.count() - 1) {
|
|
||||||
// We are just painting the header for the last column. Check if there
|
|
||||||
// is some empty space to the right which needs to be filled.
|
|
||||||
if (rect.right() < size().width()) {
|
|
||||||
option.position = QStyleOptionHeader::Middle;
|
|
||||||
paintBackgroundForEmptyArea = true;
|
|
||||||
} else {
|
|
||||||
option.position = QStyleOptionHeader::End;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
option.position = QStyleOptionHeader::Middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
option.orientation = Qt::Horizontal;
|
option.orientation = Qt::Horizontal;
|
||||||
option.selectedPosition = QStyleOptionHeader::NotAdjacent;
|
option.selectedPosition = QStyleOptionHeader::NotAdjacent;
|
||||||
option.text = m_model->roleDescription(role);
|
option.text = m_model->roleDescription(role);
|
||||||
|
|
||||||
style()->drawControl(QStyle::CE_Header, &option, painter, widget);
|
// First we paint any potential empty (padding) space on left and/or right of this role's column.
|
||||||
|
const auto paintPadding = [&](int section, const QRectF &rect, const QStyleOptionHeader::SectionPosition &pos){
|
||||||
|
QStyleOptionHeader padding;
|
||||||
|
padding.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal;
|
||||||
|
padding.section = section;
|
||||||
|
padding.sortIndicator = QStyleOptionHeader::None;
|
||||||
|
padding.rect = rect.toRect();
|
||||||
|
padding.position = pos;
|
||||||
|
padding.text = QString();
|
||||||
|
style()->drawControl(QStyle::CE_Header, &padding, painter, widget);
|
||||||
|
};
|
||||||
|
|
||||||
if (paintBackgroundForEmptyArea) {
|
if (m_columns.count() == 1) {
|
||||||
option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal;
|
option.position = QStyleOptionHeader::Middle;
|
||||||
option.section = m_columns.count();
|
paintPadding(0, QRectF(0.0, 0.0, rect.left(), rect.height()), QStyleOptionHeader::Beginning);
|
||||||
option.sortIndicator = QStyleOptionHeader::None;
|
paintPadding(1, QRectF(rect.left(), 0.0, size().width() - rect.left(), rect.height()), QStyleOptionHeader::End);
|
||||||
|
} else if (orderIndex == 0) {
|
||||||
qreal backgroundRectX = rect.x() + rect.width();
|
// Paint the header for the first column; check if there is some empty space to the left which needs to be filled.
|
||||||
QRectF backgroundRect(backgroundRectX, 0.0, size().width() - backgroundRectX, rect.height());
|
if (rect.left() > 0) {
|
||||||
option.rect = backgroundRect.toRect();
|
option.position = QStyleOptionHeader::Middle;
|
||||||
option.position = QStyleOptionHeader::End;
|
paintPadding(0,QRectF(0.0, 0.0, rect.left(), rect.height()), QStyleOptionHeader::Beginning);
|
||||||
option.text = QString();
|
} else {
|
||||||
|
option.position = QStyleOptionHeader::Beginning;
|
||||||
style()->drawControl(QStyle::CE_Header, &option, painter, widget);
|
|
||||||
}
|
}
|
||||||
|
} else if (orderIndex == m_columns.count() - 1) {
|
||||||
|
// Paint the header for the last column; check if there is some empty space to the right which needs to be filled.
|
||||||
|
if (rect.right() < size().width()) {
|
||||||
|
option.position = QStyleOptionHeader::Middle;
|
||||||
|
paintPadding(m_columns.count(), QRectF(rect.left(), 0.0, size().width() - rect.left(), rect.height()), QStyleOptionHeader::End);
|
||||||
|
} else {
|
||||||
|
option.position = QStyleOptionHeader::End;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
option.position = QStyleOptionHeader::Middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
style()->drawControl(QStyle::CE_Header, &option, painter, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF& pos)
|
void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF& pos)
|
||||||
|
@ -467,7 +504,7 @@ int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const
|
||||||
{
|
{
|
||||||
int index = -1;
|
int index = -1;
|
||||||
|
|
||||||
qreal x = -m_offset;
|
qreal x = -m_offset + m_leadingPadding;
|
||||||
for (const QByteArray& role : qAsConst(m_columns)) {
|
for (const QByteArray& role : qAsConst(m_columns)) {
|
||||||
++index;
|
++index;
|
||||||
x += m_columnWidths.value(role);
|
x += m_columnWidths.value(role);
|
||||||
|
@ -481,7 +518,7 @@ int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const
|
||||||
|
|
||||||
bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) const
|
bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) const
|
||||||
{
|
{
|
||||||
qreal x = -m_offset;
|
qreal x = -m_offset + m_leadingPadding;
|
||||||
for (int i = 0; i <= roleIndex; ++i) {
|
for (int i = 0; i <= roleIndex; ++i) {
|
||||||
const QByteArray role = m_columns[i];
|
const QByteArray role = m_columns[i];
|
||||||
x += m_columnWidths.value(role);
|
x += m_columnWidths.value(role);
|
||||||
|
@ -491,6 +528,27 @@ bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) c
|
||||||
return pos.x() >= (x - grip) && pos.x() <= x;
|
return pos.x() >= (x - grip) && pos.x() <= x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool KItemListHeaderWidget::isAbovePaddingGrip(const QPointF& pos, PaddingGrip paddingGrip) const
|
||||||
|
{
|
||||||
|
const qreal lx = -m_offset + m_leadingPadding;
|
||||||
|
const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
|
||||||
|
|
||||||
|
switch (paddingGrip) {
|
||||||
|
case Leading:
|
||||||
|
return pos.x() >= (lx - grip) && pos.x() <= lx;
|
||||||
|
case Trailing:
|
||||||
|
{
|
||||||
|
qreal rx = lx;
|
||||||
|
for (const QByteArray& role : qAsConst(m_columns)) {
|
||||||
|
rx += m_columnWidths.value(role);
|
||||||
|
}
|
||||||
|
return pos.x() >= (rx - grip) && pos.x() <= rx;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const
|
QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const
|
||||||
{
|
{
|
||||||
const QByteArray role = m_columns[roleIndex];
|
const QByteArray role = m_columns[roleIndex];
|
||||||
|
@ -522,7 +580,7 @@ int KItemListHeaderWidget::targetOfMovingRole() const
|
||||||
const int movingRight = movingLeft + movingWidth - 1;
|
const int movingRight = movingLeft + movingWidth - 1;
|
||||||
|
|
||||||
int targetIndex = 0;
|
int targetIndex = 0;
|
||||||
qreal targetLeft = -m_offset;
|
qreal targetLeft = -m_offset + m_leadingPadding;
|
||||||
while (targetIndex < m_columns.count()) {
|
while (targetIndex < m_columns.count()) {
|
||||||
const QByteArray role = m_columns[targetIndex];
|
const QByteArray role = m_columns[targetIndex];
|
||||||
const qreal targetWidth = m_columnWidths.value(role);
|
const qreal targetWidth = m_columnWidths.value(role);
|
||||||
|
@ -548,7 +606,7 @@ int KItemListHeaderWidget::targetOfMovingRole() const
|
||||||
|
|
||||||
qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const
|
qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const
|
||||||
{
|
{
|
||||||
qreal x = -m_offset;
|
qreal x = -m_offset + m_leadingPadding;
|
||||||
for (const QByteArray& visibleRole : qAsConst(m_columns)) {
|
for (const QByteArray& visibleRole : qAsConst(m_columns)) {
|
||||||
if (visibleRole == role) {
|
if (visibleRole == role) {
|
||||||
return x;
|
return x;
|
||||||
|
|
|
@ -50,6 +50,9 @@ public:
|
||||||
void setOffset(qreal offset);
|
void setOffset(qreal offset);
|
||||||
qreal offset() const;
|
qreal offset() const;
|
||||||
|
|
||||||
|
void setLeadingPadding(qreal width);
|
||||||
|
qreal leadingPadding() const;
|
||||||
|
|
||||||
qreal minimumColumnWidth() const;
|
qreal minimumColumnWidth() const;
|
||||||
|
|
||||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override;
|
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override;
|
||||||
|
@ -63,6 +66,8 @@ Q_SIGNALS:
|
||||||
qreal currentWidth,
|
qreal currentWidth,
|
||||||
qreal previousWidth);
|
qreal previousWidth);
|
||||||
|
|
||||||
|
void leadingPaddingChanged(qreal width);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is emitted if the user has released the mouse button after adjusting the
|
* Is emitted if the user has released the mouse button after adjusting the
|
||||||
* width of a visible role.
|
* width of a visible role.
|
||||||
|
@ -105,6 +110,13 @@ private Q_SLOTS:
|
||||||
void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous);
|
void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
enum PaddingGrip
|
||||||
|
{
|
||||||
|
Leading,
|
||||||
|
Trailing,
|
||||||
|
};
|
||||||
|
|
||||||
void paintRole(QPainter* painter,
|
void paintRole(QPainter* painter,
|
||||||
const QByteArray& role,
|
const QByteArray& role,
|
||||||
const QRectF& rect,
|
const QRectF& rect,
|
||||||
|
@ -115,6 +127,7 @@ private:
|
||||||
void updateHoveredRoleIndex(const QPointF& pos);
|
void updateHoveredRoleIndex(const QPointF& pos);
|
||||||
int roleIndexAt(const QPointF& pos) const;
|
int roleIndexAt(const QPointF& pos) const;
|
||||||
bool isAboveRoleGrip(const QPointF& pos, int roleIndex) const;
|
bool isAboveRoleGrip(const QPointF& pos, int roleIndex) const;
|
||||||
|
bool isAbovePaddingGrip(const QPointF& pos, PaddingGrip paddingGrip) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a pixmap of the role with the index \a roleIndex that is shown
|
* Creates a pixmap of the role with the index \a roleIndex that is shown
|
||||||
|
@ -138,12 +151,14 @@ private:
|
||||||
{
|
{
|
||||||
NoRoleOperation,
|
NoRoleOperation,
|
||||||
ResizeRoleOperation,
|
ResizeRoleOperation,
|
||||||
|
ResizeLeadingColumnOperation,
|
||||||
MoveRoleOperation
|
MoveRoleOperation
|
||||||
};
|
};
|
||||||
|
|
||||||
bool m_automaticColumnResizing;
|
bool m_automaticColumnResizing;
|
||||||
KItemModelBase* m_model;
|
KItemModelBase* m_model;
|
||||||
qreal m_offset;
|
qreal m_offset;
|
||||||
|
qreal m_leadingPadding;
|
||||||
QList<QByteArray> m_columns;
|
QList<QByteArray> m_columns;
|
||||||
QHash<QByteArray, qreal> m_columnWidths;
|
QHash<QByteArray, qreal> m_columnWidths;
|
||||||
QHash<QByteArray, qreal> m_preferredColumnWidths;
|
QHash<QByteArray, qreal> m_preferredColumnWidths;
|
||||||
|
|
|
@ -40,6 +40,10 @@
|
||||||
<label>Position of columns</label>
|
<label>Position of columns</label>
|
||||||
<default>0,1,2,3,4,5,6,7,8</default>
|
<default>0,1,2,3,4,5,6,7,8</default>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="LeadingPadding" type="UInt">
|
||||||
|
<label>Leading Column Padding</label>
|
||||||
|
<default>20</default>
|
||||||
|
</entry>
|
||||||
<entry name="ExpandableFolders" type="Bool">
|
<entry name="ExpandableFolders" type="Bool">
|
||||||
<label>Expandable folders</label>
|
<label>Expandable folders</label>
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
|
|
|
@ -73,6 +73,7 @@ void DolphinItemListView::readSettings()
|
||||||
beginTransaction();
|
beginTransaction();
|
||||||
|
|
||||||
setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
|
setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
|
||||||
|
setHighlightEntireRow(DetailsModeSettings::leadingPadding());
|
||||||
setSupportsItemExpanding(itemLayoutSupportsItemExpanding(itemLayout()));
|
setSupportsItemExpanding(itemLayoutSupportsItemExpanding(itemLayout()));
|
||||||
|
|
||||||
updateFont();
|
updateFont();
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "dolphinview.h"
|
#include "dolphinview.h"
|
||||||
|
|
||||||
#include "dolphin_generalsettings.h"
|
#include "dolphin_generalsettings.h"
|
||||||
|
#include "dolphin_detailsmodesettings.h"
|
||||||
#include "dolphinitemlistview.h"
|
#include "dolphinitemlistview.h"
|
||||||
#include "dolphinnewfilemenuobserver.h"
|
#include "dolphinnewfilemenuobserver.h"
|
||||||
#include "draganddrophelper.h"
|
#include "draganddrophelper.h"
|
||||||
|
@ -201,6 +202,8 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
|
||||||
this, &DolphinView::slotRoleEditingCanceled);
|
this, &DolphinView::slotRoleEditingCanceled);
|
||||||
connect(m_view->header(), &KItemListHeader::columnWidthChangeFinished,
|
connect(m_view->header(), &KItemListHeader::columnWidthChangeFinished,
|
||||||
this, &DolphinView::slotHeaderColumnWidthChangeFinished);
|
this, &DolphinView::slotHeaderColumnWidthChangeFinished);
|
||||||
|
connect(m_view->header(), &KItemListHeader::leadingPaddingChanged,
|
||||||
|
this, &DolphinView::slotLeadingPaddingWidthChanged);
|
||||||
|
|
||||||
KItemListSelectionManager* selectionManager = controller->selectionManager();
|
KItemListSelectionManager* selectionManager = controller->selectionManager();
|
||||||
connect(selectionManager, &KItemListSelectionManager::selectionChanged,
|
connect(selectionManager, &KItemListSelectionManager::selectionChanged,
|
||||||
|
@ -1117,6 +1120,10 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos)
|
||||||
QActionGroup* widthsGroup = new QActionGroup(menu);
|
QActionGroup* widthsGroup = new QActionGroup(menu);
|
||||||
const bool autoColumnWidths = props.headerColumnWidths().isEmpty();
|
const bool autoColumnWidths = props.headerColumnWidths().isEmpty();
|
||||||
|
|
||||||
|
QAction* toggleLeadingPaddingAction = menu->addAction(i18nc("@action:inmenu", "Leading Column Padding"));
|
||||||
|
toggleLeadingPaddingAction->setCheckable(true);
|
||||||
|
toggleLeadingPaddingAction->setChecked(view->header()->leadingPadding() > 0);
|
||||||
|
|
||||||
QAction* autoAdjustWidthsAction = menu->addAction(i18nc("@action:inmenu", "Automatic Column Widths"));
|
QAction* autoAdjustWidthsAction = menu->addAction(i18nc("@action:inmenu", "Automatic Column Widths"));
|
||||||
autoAdjustWidthsAction->setCheckable(true);
|
autoAdjustWidthsAction->setCheckable(true);
|
||||||
autoAdjustWidthsAction->setChecked(autoColumnWidths);
|
autoAdjustWidthsAction->setChecked(autoColumnWidths);
|
||||||
|
@ -1147,6 +1154,8 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos)
|
||||||
}
|
}
|
||||||
props.setHeaderColumnWidths(columnWidths);
|
props.setHeaderColumnWidths(columnWidths);
|
||||||
header->setAutomaticColumnResizing(false);
|
header->setAutomaticColumnResizing(false);
|
||||||
|
} else if (action == toggleLeadingPaddingAction) {
|
||||||
|
header->setLeadingPadding(toggleLeadingPaddingAction->isChecked() ? 20 : 0);
|
||||||
} else {
|
} else {
|
||||||
// Show or hide the selected role
|
// Show or hide the selected role
|
||||||
const QByteArray selectedRole = action->data().toByteArray();
|
const QByteArray selectedRole = action->data().toByteArray();
|
||||||
|
@ -1199,6 +1208,13 @@ void DolphinView::slotHeaderColumnWidthChangeFinished(const QByteArray& role, qr
|
||||||
props.setHeaderColumnWidths(columnWidths);
|
props.setHeaderColumnWidths(columnWidths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DolphinView::slotLeadingPaddingWidthChanged(qreal width)
|
||||||
|
{
|
||||||
|
ViewProperties props(viewPropertiesUrl());
|
||||||
|
DetailsModeSettings::setLeadingPadding(int(width));
|
||||||
|
m_view->writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
void DolphinView::slotItemHovered(int index)
|
void DolphinView::slotItemHovered(int index)
|
||||||
{
|
{
|
||||||
const KFileItem item = m_model->fileItem(index);
|
const KFileItem item = m_model->fileItem(index);
|
||||||
|
@ -1992,6 +2008,7 @@ void DolphinView::applyViewProperties(const ViewProperties& props)
|
||||||
} else {
|
} else {
|
||||||
header->setAutomaticColumnResizing(true);
|
header->setAutomaticColumnResizing(true);
|
||||||
}
|
}
|
||||||
|
header->setLeadingPadding(DetailsModeSettings::leadingPadding());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_view->endTransaction();
|
m_view->endTransaction();
|
||||||
|
|
|
@ -635,6 +635,7 @@ private Q_SLOTS:
|
||||||
void slotViewContextMenuRequested(const QPointF& pos);
|
void slotViewContextMenuRequested(const QPointF& pos);
|
||||||
void slotHeaderContextMenuRequested(const QPointF& pos);
|
void slotHeaderContextMenuRequested(const QPointF& pos);
|
||||||
void slotHeaderColumnWidthChangeFinished(const QByteArray& role, qreal current);
|
void slotHeaderColumnWidthChangeFinished(const QByteArray& role, qreal current);
|
||||||
|
void slotLeadingPaddingWidthChanged(qreal width);
|
||||||
void slotItemHovered(int index);
|
void slotItemHovered(int index);
|
||||||
void slotItemUnhovered(int index);
|
void slotItemUnhovered(int index);
|
||||||
void slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event);
|
void slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event);
|
||||||
|
|
Loading…
Reference in a new issue