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 | |
19 | KDirOperatorIconView::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 | |
47 | KDirOperatorIconView::~KDirOperatorIconView() |
48 | { |
49 | } |
50 | |
51 | void KDirOperatorIconView::resizeEvent(QResizeEvent *event) |
52 | { |
53 | Q_UNUSED(event); |
54 | |
55 | updateLayout(); |
56 | } |
57 | |
58 | void 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 | |
71 | void KDirOperatorIconView::dragEnterEvent(QDragEnterEvent *event) |
72 | { |
73 | if (event->mimeData()->hasUrls()) { |
74 | event->acceptProposedAction(); |
75 | } |
76 | } |
77 | |
78 | void 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 | |
98 | void 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 | |
107 | void 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 | |
116 | void 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 | |
136 | void 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 | } |
173 | void KDirOperatorIconView::setDecorationPosition(QStyleOptionViewItem::Position newDecorationPosition) |
174 | { |
175 | decorationPosition = newDecorationPosition; |
176 | updateLayout(); |
177 | } |
178 | |
179 | #include "moc_kdiroperatoriconview_p.cpp" |
180 | |