Marble

PluginItemDelegate.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2009 Bastian Holst <bastianholst@gmx.de>
4//
5
6// Self
7#include "PluginItemDelegate.h"
8
9// Marble
10#include "RenderPluginModel.h"
11#include "MarbleDebug.h"
12
13// Qt
14#include <QEvent>
15#include <QSize>
16#include <QVariant>
17#include <QAbstractItemView>
18#include <QMouseEvent>
19#include <QStandardItemModel>
20#include <QApplication>
21#include <QPainter>
22
23using namespace Marble;
24/* TRANSLATOR Marble::PluginItemDelegate */
25
26const QSize iconSize( 16, 16 );
27
28PluginItemDelegate::PluginItemDelegate( QAbstractItemView *view, QObject * parent )
29 : QAbstractItemDelegate( parent )
30{
31 // Enable mouse tracking of itemview makes it possible to find when the mouse if moved
32 // without pressed buttons.
33 view->setMouseTracking( true );
34}
35
36PluginItemDelegate::~PluginItemDelegate()
37{
38}
39
40void PluginItemDelegate::paint( QPainter *painter,
41 const QStyleOptionViewItem& option,
42 const QModelIndex& index ) const
43{
44 Q_ASSERT( index.isValid() );
45 QRect rect = option.rect;
46 QStyle *style = QApplication::style();
47
48 painter->save();
49
50 // Drawing the background
51 QStyleOption background = option;
52 style->drawPrimitive( QStyle::PE_PanelItemViewItem, &option, painter );
53
54 painter->translate( rect.topLeft() );
55
56 // rect is now represented in item coordinates
57 rect.moveTopLeft( QPoint( 0, 0 ) );
58 // The point at the top left of the available drawing area.
59 QPoint topLeft( 0, 0 );
60 // The point at the top right of the available drawing area.
61 QPoint topRight( rect.topRight() );
62
63 QRect nameRect = rect;
64
65 // Painting the checkbox
66 QStyleOptionButton checkBox = checkboxOption( option, index, topLeft.x(), Qt::AlignLeft );
67 painter->save();
68 style->drawControl( QStyle::CE_CheckBox, &checkBox, painter );
69 painter->restore();
70
71 nameRect.setLeft( checkBox.rect.right() + 1 );
72
73 // Painting the About Button
74 QStyleOptionButton button = buttonOption( option, index, PluginItemDelegate::About,
75 topRight.x(), Qt::AlignRight );
76 style->drawControl( QStyle::CE_PushButton, &button, painter );
77 topRight -= QPoint( button.rect.width(), 0 );
78
79 // Painting the Configure Button
80 if ( index.data( RenderPluginModel::ConfigurationDialogAvailable ).toBool() ) {
81 QStyleOptionButton button = buttonOption( option, index, PluginItemDelegate::Configure,
82 topRight.x(), Qt::AlignRight );
83 style->drawControl( QStyle::CE_PushButton, &button, painter );
84 topRight -= QPoint( button.rect.width(), 0 );
85
86 nameRect.setRight( button.rect.left() -1 );
87 }
88
89 // Painting the Icon
90 const QIcon icon = index.data( Qt::DecorationRole ).value<QIcon>();
91 const QPixmap iconPixmap = icon.pixmap(16, 16);
92
93 nameRect.moveBottom( nameRect.bottom()+5 );
94 style->drawItemPixmap( painter,
97 iconPixmap );
98
99 nameRect.setLeft( nameRect.left() + 16 + 5 );
100 nameRect.moveBottom( nameRect.bottom()-5 );
101
102 // Painting the Name string
104
105 style->drawItemText( painter,
106 nameRect,
108 option.palette,
109 true,
110 name );
111
112 painter->restore();
113}
114
115QSize PluginItemDelegate::sizeHint( const QStyleOptionViewItem& option,
116 const QModelIndex & index ) const
117{
118 QSize size;
119
120 QStyleOptionViewItem opt = option;
121 opt.rect = QRect( 0, 0, 0, 0 );
122 QVector<QSize> elementSize;
123 elementSize.reserve(4);
124 QStyleOptionButton checkBox = checkboxOption( opt, index );
125 elementSize.append( checkBox.rect.size() );
126 QStyleOptionButton aboutButton = buttonOption( opt, index, PluginItemDelegate::About );
127 elementSize.append( aboutButton.rect.size() );
128 QStyleOptionButton configButton = buttonOption( opt, index, PluginItemDelegate::Configure );
129 elementSize.append( configButton.rect.size() );
130 elementSize.append( nameSize( index ) );
131
132 for( const QSize& buttonSize: elementSize ) {
133 if( buttonSize.height() > size.height() )
134 size.setHeight( buttonSize.height() );
135 size.setWidth( size.width() + buttonSize.width() );
136 }
137
138 return size;
139}
140
141void PluginItemDelegate::setAboutIcon( const QIcon& icon )
142{
143 m_aboutIcon = icon;
144}
145
146void PluginItemDelegate::setConfigIcon( const QIcon& icon )
147{
148 m_configIcon = icon;
149}
150
151bool PluginItemDelegate::editorEvent( QEvent *event,
152 QAbstractItemModel *model,
153 const QStyleOptionViewItem &option,
154 const QModelIndex &index )
155{
157 Q_ASSERT(model);
158
159 if ( ( event->type() == QEvent::MouseButtonRelease )
160 || ( event->type() == QEvent::MouseButtonDblClick )
161 || ( event->type() == QEvent::MouseButtonPress )
162 || ( event->type() == QEvent::MouseMove ) )
163 {
164 QMouseEvent *me = static_cast<QMouseEvent*>(event);
165 QPoint mousePosition = me->pos() - option.rect.topLeft();
166
167 if ( ( event->type() == QEvent::MouseMove )
168 && !( me->buttons() & Qt::LeftButton ) )
169 {
170 // If the mouse moves around and no left button is pressed, no pushbutton is pressed
171 // and no other event will be successful.
172 m_aboutPressedIndex = QModelIndex();
173 m_configPressedIndex = QModelIndex();
174 return true;
175 }
176
177 // Handle checkbox
178 QRect checkRect = checkboxOption( option, index, 0, Qt::AlignLeft ).rect;
179 if ( checkRect.contains( mousePosition )
180 && ( ( event->type() == QEvent::MouseButtonDblClick )
181 || ( event->type() == QEvent::MouseButtonRelease ) ) )
182 {
183 // make sure that the item is checkable
184 Qt::ItemFlags flags = model->flags(index);
185 if ( !( flags & Qt::ItemIsUserCheckable ) || !( option.state & QStyle::State_Enabled )
186 || !( flags & Qt::ItemIsEnabled ) )
187 return false;
188
189 // make sure that we have a check state
191 if ( !checkValue.isValid() )
192 return false;
193
194 // eat the double click events inside the check rect
195 if ( event->type() == QEvent::MouseButtonDblClick )
196 return true;
197
198 Qt::CheckState state = ( static_cast<Qt::CheckState>( checkValue.toInt() ) == Qt::Checked
199 ? Qt::Unchecked : Qt::Checked );
200 return model->setData(index, state, Qt::CheckStateRole);
201 }
202
203 if ( ( event->type() == QEvent::MouseMove )
204 && !( me->buttons() & Qt::LeftButton ) )
205 {
206 m_aboutPressedIndex = QModelIndex();
207 m_configPressedIndex = QModelIndex();
208 return true;
209 }
210
211 QPoint topRight = option.rect.topRight();
212
213 // Handle aboutButton
214 {
215 QRect aboutRect = buttonOption( option,
216 index,
217 PluginItemDelegate::About,
218 topRight.x(),
219 Qt::AlignRight ).rect;
220 if ( aboutRect.contains( mousePosition ) ) {
221 if ( event->type() == QEvent::MouseButtonDblClick )
222 return true;
223 if ( event->type() == QEvent::MouseButtonPress ) {
224 m_aboutPressedIndex = index;
225 m_configPressedIndex = QModelIndex();
226 return true;
227 }
228 if ( event->type() == QEvent::MouseButtonRelease ) {
229 m_aboutPressedIndex = QModelIndex();
230 m_configPressedIndex = QModelIndex();
231 emit aboutPluginClicked( index );
232 return true;
233 }
234 if ( event->type() == QEvent::MouseMove ) {
235 if ( me->buttons() & Qt::LeftButton ) {
236 m_aboutPressedIndex = index;
237 m_configPressedIndex = QModelIndex();
238 return true;
239 }
240 else {
241 m_aboutPressedIndex = QModelIndex();
242 m_configPressedIndex = QModelIndex();
243 return true;
244 }
245 }
246 }
247 else {
248 // If the mouse is on the item and the mouse isn't above the button.
249 // no about button is pressed.
250 m_aboutPressedIndex = QModelIndex();
251 }
252 topRight -= QPoint( aboutRect.width(), 0 );
253 }
254
255 // Handle configButton
256 // make sure we have config button
257 if ( index.data( RenderPluginModel::ConfigurationDialogAvailable ).toBool() ) {
258 QRect configRect = buttonOption( option,
259 index,
260 PluginItemDelegate::Configure,
261 topRight.x(),
262 Qt::AlignRight ).rect;
263 if( configRect.contains( mousePosition ) ) {
264 if ( event->type() == QEvent::MouseButtonDblClick )
265 return true;
266
267 if ( event->type() == QEvent::MouseButtonPress ) {
268 m_aboutPressedIndex = QModelIndex();
269 m_configPressedIndex = index;
270 return true;
271 }
272 if ( event->type() == QEvent::MouseButtonRelease ) {
273 m_aboutPressedIndex = QModelIndex();
274 m_configPressedIndex = QModelIndex();
275 emit configPluginClicked( index );
276 return true;
277 }
278 if ( event->type() == QEvent::MouseMove ) {
279 if ( me->buttons() & Qt::LeftButton ) {
280 m_aboutPressedIndex = QModelIndex();
281 m_configPressedIndex = index;
282 return true;
283 }
284 else {
285 m_aboutPressedIndex = QModelIndex();
286 m_configPressedIndex = QModelIndex();
287 return true;
288 }
289 }
290 }
291 else {
292 // If the mouse is on the item and the mouse isn't above the button.
293 // no config button is pressed.
294 m_configPressedIndex = QModelIndex();
295 }
296
297 topRight -= QPoint( configRect.width(), 0 );
298 }
299 else {
300 // If we don't have an config dialog shown and the mouse is over this item,
301 // no config button is pressed.
302 m_configPressedIndex = QModelIndex();
303 }
304 }
305
306 return false;
307}
308
309QStyleOptionButton PluginItemDelegate::checkboxOption( const QStyleOptionViewItem& option,
310 const QModelIndex& index,
311 int position,
312 Qt::AlignmentFlag alignment )
313{
315 if ( index.data( Qt::CheckStateRole ).toBool() )
316 styleOptionButton.state = option.state | QStyle::State_On;
317 else
318 styleOptionButton.state = option.state | QStyle::State_Off;
320 if ( size.isEmpty() ) {
321 // A checkbox has definitely a size != 0
322 styleOptionButton.rect.setSize( QSize( 22, 22 ) );
323 }
324 else {
325 styleOptionButton.rect.setSize( QSize( size.width(), size.height() ) );
326 }
327 styleOptionButton.rect = alignRect( styleOptionButton.rect, option.rect, position, alignment );
328 return styleOptionButton;
329}
330
331QStyleOptionButton PluginItemDelegate::buttonOption( const QStyleOptionViewItem& option,
332 const QModelIndex& index,
333 PluginItemDelegate::ButtonType type,
334 int position,
335 Qt::AlignmentFlag alignment ) const
336{
337 QStyleOptionButton buttonOption;
338 buttonOption.state = option.state;
339 buttonOption.state &= ~QStyle::State_HasFocus;
340
341 buttonOption.rect.setTopLeft( QPoint( 0, 0 ) );
342 buttonOption.palette = option.palette;
343 buttonOption.features = QStyleOptionButton::None;
344
345 QSize contentSize;
346 if ( type == PluginItemDelegate::About ) {
347 if ( m_aboutIcon.isNull() ) {
348 buttonOption.text = tr( "About" );
349 contentSize = buttonOption.fontMetrics.size( 0, buttonOption.text ) + QSize( 4, 4 );
350 }
351 else {
352 buttonOption.icon = m_aboutIcon;
353 buttonOption.iconSize = iconSize;
354 contentSize = iconSize;
355 }
356
357 if ( m_aboutPressedIndex == index ) {
358 buttonOption.state |= QStyle::State_Sunken;
359 }
360 }
361 else if ( type == PluginItemDelegate::Configure ) {
362 if ( m_configIcon.isNull() ) {
363 buttonOption.text = tr( "Configure" );
364 contentSize = buttonOption.fontMetrics.size( 0, buttonOption.text ) + QSize( 4, 4 );
365 }
366 else {
367 buttonOption.icon = m_configIcon;
368 buttonOption.iconSize = iconSize;
369 contentSize = iconSize;
370 }
371 if ( m_configPressedIndex == index ) {
372 buttonOption.state |= QStyle::State_Sunken;
373 }
374 }
375
377 &buttonOption,
378 contentSize );
379 buttonOption.rect.setSize( buttonSize );
380 buttonOption.rect = alignRect( buttonOption.rect, option.rect, position, alignment );
381 return buttonOption;
382}
383
384QSize PluginItemDelegate::nameSize( const QModelIndex& index )
385{
387 // FIXME: QApplication::fontMetrics() doesn't work for non-application fonts
388 QSize nameSize( QApplication::fontMetrics().size( 0, name ) );
389 return nameSize;
390}
391
392QRect PluginItemDelegate::alignRect( const QRect& object,
393 const QRect& frame,
394 int position,
395 Qt::AlignmentFlag alignment )
396{
397 QRect rect = object;
398
399 rect.setTopLeft( QPoint( 0, 0 ) );
400 // Moves the object to the middle of the item.
401 if ( rect.height() < frame.height() ) {
402 rect.moveTop( ( frame.height() - rect.height() ) / 2 );
403 }
404
405 if ( alignment & Qt::AlignLeft ) {
406 rect.moveLeft( position );
407 }
408 else if ( alignment & Qt::AlignRight ) {
409 rect.moveRight( position );
410 }
411
412 return rect;
413}
414
415
416#include "moc_PluginItemDelegate.cpp"
QString name(StandardShortcut id)
Binds a QML item to a specific geodetic location in screen coordinates.
virtual Qt::ItemFlags flags(const QModelIndex &index) const const
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
QFontMetrics fontMetrics()
QStyle * style()
MouseButtonRelease
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
bool isNull() const const
void append(QList< T > &&value)
void reserve(qsizetype size)
QVariant data(int role) const const
bool isValid() const const
virtual bool event(QEvent *e)
T qobject_cast(QObject *object)
QString tr(const char *sourceText, const char *disambiguation, int n)
void restore()
void save()
void translate(const QPoint &offset)
int x() const const
int height() const const
void moveLeft(int x)
void moveRight(int x)
void moveTop(int y)
void moveTopLeft(const QPoint &position)
void setTopLeft(const QPoint &position)
QPoint topLeft() const const
QPoint topRight() const const
int height() const const
bool isEmpty() const const
void setHeight(int height)
void setWidth(int width)
int width() const const
PE_PanelItemViewItem
virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const const
virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const const
virtual void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const const=0
AlignLeft
CheckState
DecorationRole
typedef ItemFlags
LeftButton
bool toBool() const const
QString toString() const const
T value() const const
void setMouseTracking(bool enable)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.