1/*
2 SPDX-FileCopyrightText: 2007 Peter Penz <peter.penz@gmx.at>
3 SPDX-FileCopyrightText: 2019 Méven Car <meven.car@kdemail.net>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "kdiroperatoriconview_p.h"
9#include "kfileitemselectionemblem.h"
10
11#include <QApplication>
12#include <QDragEnterEvent>
13#include <QMimeData>
14#include <QScrollBar>
15
16#include <KFileItemDelegate>
17#include <KIconLoader>
18
19KDirOperatorIconView::KDirOperatorIconView(KDirOperator *dirOperator, QWidget *parent, QStyleOptionViewItem::Position aDecorationPosition)
20 : QListView(parent)
21 , m_isEmblemClicked(false)
22 , m_dirOperator(dirOperator)
23{
24 setViewMode(QListView::IconMode);
25 setResizeMode(QListView::Adjust);
26 setSpacing(0);
27 setMovement(QListView::Static);
28 setDragDropMode(QListView::DragOnly);
29 setVerticalScrollMode(QListView::ScrollPerPixel);
30 setHorizontalScrollMode(QListView::ScrollPerPixel);
31 setEditTriggers(QAbstractItemView::NoEditTriggers);
32 setWordWrap(true);
33 setIconSize(QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall));
34
35 decorationPosition = aDecorationPosition;
36
37 const QFontMetrics metrics(viewport()->font());
38 const int singleStep = metrics.height() * QApplication::wheelScrollLines();
39
40 verticalScrollBar()->setSingleStep(singleStep);
41 horizontalScrollBar()->setSingleStep(singleStep);
42
43 updateLayout();
44 connect(sender: this, signal: &QListView::iconSizeChanged, context: this, slot: &KDirOperatorIconView::updateLayout);
45}
46
47KDirOperatorIconView::~KDirOperatorIconView()
48{
49}
50
51void KDirOperatorIconView::resizeEvent(QResizeEvent *event)
52{
53 Q_UNUSED(event);
54
55 updateLayout();
56}
57
58void KDirOperatorIconView::initViewItemOption(QStyleOptionViewItem *option) const
59{
60 QListView::initViewItemOption(option);
61 option->showDecorationSelected = true;
62 option->textElideMode = Qt::ElideMiddle;
63 option->decorationPosition = decorationPosition;
64 if (option->decorationPosition == QStyleOptionViewItem::Left) {
65 option->displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
66 } else {
67 option->displayAlignment = Qt::AlignCenter;
68 }
69}
70
71void KDirOperatorIconView::dragEnterEvent(QDragEnterEvent *event)
72{
73 if (event->mimeData()->hasUrls()) {
74 event->acceptProposedAction();
75 }
76}
77
78void KDirOperatorIconView::mousePressEvent(QMouseEvent *event)
79{
80 const QModelIndex index = indexAt(p: event->pos());
81
82 // When selection emblem is clicked, select it and don't do anything else
83 m_isEmblemClicked = KFileItemSelectionEmblem(this, index, m_dirOperator).handleMousePressEvent(mousePos: event->pos());
84 if (m_isEmblemClicked) {
85 return;
86 }
87
88 if (!index.isValid()) {
89 const Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
90 if (!(modifiers & Qt::ShiftModifier) && !(modifiers & Qt::ControlModifier)) {
91 clearSelection();
92 }
93 }
94
95 QListView::mousePressEvent(event);
96}
97
98void KDirOperatorIconView::mouseMoveEvent(QMouseEvent *event)
99{
100 // Disallow selection dragging when emblem is clicked
101 if (m_isEmblemClicked) {
102 return;
103 }
104 QListView::mouseMoveEvent(e: event);
105}
106
107void KDirOperatorIconView::mouseReleaseEvent(QMouseEvent *event)
108{
109 // Reset the emblem selection
110 if (m_isEmblemClicked) {
111 m_isEmblemClicked = false;
112 }
113 QListView::mouseReleaseEvent(e: event);
114}
115
116void KDirOperatorIconView::wheelEvent(QWheelEvent *event)
117{
118 QListView::wheelEvent(e: event);
119
120 // apply the vertical wheel event to the horizontal scrollbar, as
121 // the items are aligned from left to right
122 if (event->angleDelta().y() != 0) {
123 QWheelEvent horizEvent(event->position(),
124 event->globalPosition(),
125 QPoint(event->pixelDelta().y(), 0),
126 QPoint(event->angleDelta().y(), 0),
127 event->buttons(),
128 event->modifiers(),
129 event->phase(),
130 event->inverted(),
131 event->source());
132 QApplication::sendEvent(receiver: horizontalScrollBar(), event: &horizEvent);
133 }
134}
135
136void KDirOperatorIconView::updateLayout()
137{
138 if (decorationPosition == QStyleOptionViewItem::Position::Top) {
139 // Icons view
140 setFlow(QListView::LeftToRight);
141 const QFontMetrics metrics(viewport()->font());
142
143 const int height = iconSize().height() + metrics.height() * 2.5;
144 const int minWidth = qMax(a: height, b: metrics.height() * 5);
145
146 const int scrollBarWidth = verticalScrollBar()->sizeHint().width();
147
148 // Subtract 1 px to prevent flickering when resizing the window
149 // For Oxygen a column is missing after showing the dialog without resizing it,
150 // therefore subtract 4 more (scaled) pixels
151 const int viewPortWidth = contentsRect().width() - scrollBarWidth - 1 - 4 * devicePixelRatioF();
152 const int itemsInRow = qMax(a: 1, b: viewPortWidth / minWidth);
153 const int remainingWidth = viewPortWidth - (minWidth * itemsInRow);
154 const int width = minWidth + (remainingWidth / itemsInRow);
155
156 const QSize itemSize(width, height);
157
158 setGridSize(itemSize);
159 KFileItemDelegate *delegate = qobject_cast<KFileItemDelegate *>(object: itemDelegate());
160 if (delegate) {
161 delegate->setMaximumSize(itemSize);
162 }
163 } else {
164 // compact view
165 setFlow(QListView::TopToBottom);
166 setGridSize(QSize());
167 KFileItemDelegate *delegate = qobject_cast<KFileItemDelegate *>(object: itemDelegate());
168 if (delegate) {
169 delegate->setMaximumSize(QSize());
170 }
171 }
172}
173void KDirOperatorIconView::setDecorationPosition(QStyleOptionViewItem::Position newDecorationPosition)
174{
175 decorationPosition = newDecorationPosition;
176 updateLayout();
177}
178
179#include "moc_kdiroperatoriconview_p.cpp"
180

source code of kio/src/filewidgets/kdiroperatoriconview.cpp