2
// This file is part of the Marble Virtual Globe.
4
// This program is free software licensed under the GNU LGPL. You can
5
// find a copy of this license in LICENSE.txt in the top directory of
8
// Copyright 2009 Bastian Holst <bastianholst@gmx.de>
12
#include "PluginItemDelegate.h"
15
#include "RenderPlugin.h"
16
#include "MarbleDebug.h"
19
#include <QtCore/QEvent>
20
#include <QtCore/QSize>
21
#include <QtCore/QVariant>
22
#include <QtGui/QAbstractItemView>
23
#include <QtGui/QMouseEvent>
24
#include <QtGui/QStandardItemModel>
25
#include <QtGui/QApplication>
26
#include <QtGui/QPainter>
27
#include <QtGui/QStandardItem>
29
using namespace Marble;
30
/* TRANSLATOR Marble::PluginItemDelegate */
32
const QSize iconSize( 16, 16 );
34
PluginItemDelegate::PluginItemDelegate( QAbstractItemView *view, QObject * parent )
35
: QAbstractItemDelegate( parent )
37
// Enable mouse tracking of itemview makes it possible to find when the mouse if moved
38
// without pressed buttons.
39
view->setMouseTracking( true );
42
PluginItemDelegate::~PluginItemDelegate()
46
void PluginItemDelegate::paint( QPainter *painter,
47
const QStyleOptionViewItem& option,
48
const QModelIndex& index ) const
50
Q_ASSERT( index.isValid() );
51
QRect rect = option.rect;
52
QStyle *style = QApplication::style();
56
// Drawing the background
57
QStyleOption background = option;
58
style->drawPrimitive( QStyle::PE_PanelItemViewItem, &option, painter );
60
painter->translate( rect.topLeft() );
62
// rect is now represented in item coordinates
63
rect.moveTopLeft( QPoint( 0, 0 ) );
64
// The point at the top left of the available drawing area.
65
QPoint topLeft( 0, 0 );
66
// The point at the top right of the available drawing area.
67
QPoint topRight( rect.topRight() );
69
QRect nameRect = rect;
71
// Painting the checkbox
72
QStyleOptionButton checkBox = checkboxOption( option, index, topLeft.x(), Qt::AlignLeft );
74
style->drawControl( QStyle::CE_CheckBox, &checkBox, painter );
77
nameRect.setLeft( checkBox.rect.right() + 1 );
79
// Painting the About Button
80
if ( index.data( RenderPlugin::AboutDialogAvailable ).toBool() ) {
81
QStyleOptionButton button = buttonOption( option, index, PluginItemDelegate::About,
82
topRight.x(), Qt::AlignRight );
83
style->drawControl( QStyle::CE_PushButton, &button, painter );
84
topRight -= QPoint( button.rect.width(), 0 );
87
// Painting the Configure Button
88
if ( index.data( RenderPlugin::ConfigurationDialogAvailable ).toBool() ) {
89
QStyleOptionButton button = buttonOption( option, index, PluginItemDelegate::Configure,
90
topRight.x(), Qt::AlignRight );
91
style->drawControl( QStyle::CE_PushButton, &button, painter );
92
topRight -= QPoint( button.rect.width(), 0 );
94
nameRect.setRight( button.rect.left() -1 );
97
// Painting the Name string
98
QString name = index.data( Qt::DisplayRole ).toString();
100
style->drawItemText( painter,
102
Qt::AlignLeft | Qt::AlignVCenter,
110
QSize PluginItemDelegate::sizeHint( const QStyleOptionViewItem& option,
111
const QModelIndex & index ) const
115
QStyleOptionViewItem opt = option;
116
opt.rect = QRect( 0, 0, 0, 0 );
117
QList<QSize> elementSize;
118
QStyleOptionButton checkBox = checkboxOption( opt, index );
119
elementSize.append( checkBox.rect.size() );
120
QStyleOptionButton aboutButton = buttonOption( opt, index, PluginItemDelegate::About );
121
elementSize.append( aboutButton.rect.size() );
122
QStyleOptionButton configButton = buttonOption( opt, index, PluginItemDelegate::Configure );
123
elementSize.append( configButton.rect.size() );
124
elementSize.append( nameSize( index ) );
126
foreach( const QSize& buttonSize, elementSize ) {
127
if( buttonSize.height() > size.height() )
128
size.setHeight( buttonSize.height() );
129
size.setWidth( size.width() + buttonSize.width() );
135
void PluginItemDelegate::setAboutIcon( const QIcon& icon )
140
void PluginItemDelegate::setConfigIcon( const QIcon& icon )
145
bool PluginItemDelegate::editorEvent( QEvent *event,
146
QAbstractItemModel *model,
147
const QStyleOptionViewItem &option,
148
const QModelIndex &index )
153
if ( ( event->type() == QEvent::MouseButtonRelease )
154
|| ( event->type() == QEvent::MouseButtonDblClick )
155
|| ( event->type() == QEvent::MouseButtonPress )
156
|| ( event->type() == QEvent::MouseMove ) )
158
QMouseEvent *me = static_cast<QMouseEvent*>(event);
159
QPoint mousePosition = me->pos() - option.rect.topLeft();
161
if ( ( event->type() == QEvent::MouseMove )
162
&& !( me->buttons() & Qt::LeftButton ) )
164
// If the mouse moves around and no left button is pressed, no pushbutton is pressed
165
// and no other event will be successful.
166
m_aboutPressedPluginId.clear();
167
m_configPressedPluginId.clear();
172
QRect checkRect = checkboxOption( option, index, 0, Qt::AlignLeft ).rect;
173
if ( checkRect.contains( mousePosition )
174
&& ( ( event->type() == QEvent::MouseButtonDblClick )
175
|| ( event->type() == QEvent::MouseButtonRelease ) ) )
177
// make sure that the item is checkable
178
Qt::ItemFlags flags = model->flags(index);
179
if ( !( flags & Qt::ItemIsUserCheckable ) || !( option.state & QStyle::State_Enabled )
180
|| !( flags & Qt::ItemIsEnabled ) )
183
// make sure that we have a check state
184
QVariant checkValue = index.data( Qt::CheckStateRole );
185
if ( !checkValue.isValid() )
188
// eat the double click events inside the check rect
189
if ( event->type() == QEvent::MouseButtonDblClick )
192
Qt::CheckState state = ( static_cast<Qt::CheckState>( checkValue.toInt() ) == Qt::Checked
193
? Qt::Unchecked : Qt::Checked );
194
return model->setData(index, state, Qt::CheckStateRole);
197
if ( ( event->type() == QEvent::MouseMove )
198
&& !( me->buttons() & Qt::LeftButton ) )
200
m_aboutPressedPluginId.clear();
201
m_configPressedPluginId.clear();
205
QPoint topRight = option.rect.topRight();
207
// Handle aboutButton
208
// make sure we have a about button
209
if ( index.data( RenderPlugin::AboutDialogAvailable ).toBool() ) {
210
QRect aboutRect = buttonOption( option,
212
PluginItemDelegate::About,
214
Qt::AlignRight ).rect;
215
QString nameId = index.data( RenderPlugin::NameId ).toString();
216
if ( aboutRect.contains( mousePosition ) ) {
217
if ( event->type() == QEvent::MouseButtonDblClick )
219
if ( event->type() == QEvent::MouseButtonPress ) {
220
m_aboutPressedPluginId = nameId;
221
m_configPressedPluginId.clear();
224
if ( event->type() == QEvent::MouseButtonRelease ) {
225
m_aboutPressedPluginId.clear();
226
m_configPressedPluginId.clear();
227
emit aboutPluginClicked( nameId );
230
if ( event->type() == QEvent::MouseMove ) {
231
if ( me->buttons() & Qt::LeftButton ) {
232
m_aboutPressedPluginId = nameId;
233
m_configPressedPluginId.clear();
237
m_aboutPressedPluginId.clear();
238
m_configPressedPluginId.clear();
244
// If the mouse is on the item and the mouse isn't above the button.
245
// no about button is pressed.
246
m_aboutPressedPluginId.clear();
248
topRight -= QPoint( aboutRect.width(), 0 );
251
// If we don't have an about dialog shown and the mouse is over this item,
252
// no about button is pressed.
253
m_aboutPressedPluginId.clear();
256
// Handle configButton
257
// make sure we have config button
258
if ( index.data( RenderPlugin::ConfigurationDialogAvailable ).toBool() ) {
259
QRect configRect = buttonOption( option,
261
PluginItemDelegate::Configure,
263
Qt::AlignRight ).rect;
264
QString nameId = index.data( RenderPlugin::NameId ).toString();
265
if( configRect.contains( mousePosition ) ) {
266
if ( event->type() == QEvent::MouseButtonDblClick )
269
if ( event->type() == QEvent::MouseButtonPress ) {
270
m_aboutPressedPluginId.clear();
271
m_configPressedPluginId = nameId;
274
if ( event->type() == QEvent::MouseButtonRelease ) {
275
m_aboutPressedPluginId.clear();
276
m_configPressedPluginId.clear();
277
emit configPluginClicked( nameId );
280
if ( event->type() == QEvent::MouseMove ) {
281
if ( me->buttons() & Qt::LeftButton ) {
282
m_aboutPressedPluginId.clear();
283
m_configPressedPluginId = nameId;
287
m_aboutPressedPluginId.clear();
288
m_configPressedPluginId.clear();
294
// If the mouse is on the item and the mouse isn't above the button.
295
// no config button is pressed.
296
m_configPressedPluginId.clear();
299
topRight -= QPoint( configRect.width(), 0 );
302
// If we don't have an config dialog shown and the mouse is over this item,
303
// no config button is pressed.
304
m_configPressedPluginId.clear();
311
QStyleOptionButton PluginItemDelegate::checkboxOption( const QStyleOptionViewItem& option,
312
const QModelIndex& index,
314
Qt::AlignmentFlag alignment ) const
316
QStyleOptionButton checkboxOption;
317
if ( index.data( Qt::CheckStateRole ).toBool() )
318
checkboxOption.state = option.state | QStyle::State_On;
320
checkboxOption.state = option.state | QStyle::State_Off;
321
QSize size = QApplication::style()->sizeFromContents( QStyle::CT_CheckBox, &option, QSize() );
322
if ( size.isEmpty() ) {
323
// A checkbox has definitely a size != 0
324
checkboxOption.rect.setSize( QSize( 22, 22 ) );
327
checkboxOption.rect.setSize( QSize( size.width(), size.height() ) );
329
checkboxOption.rect = alignRect( checkboxOption.rect, option.rect, position, alignment );
330
return checkboxOption;
333
QStyleOptionButton PluginItemDelegate::buttonOption( const QStyleOptionViewItem& option,
334
const QModelIndex& index,
335
PluginItemDelegate::ButtonType type,
337
Qt::AlignmentFlag alignment ) const
339
QStyleOptionButton buttonOption;
340
buttonOption.state = option.state;
341
buttonOption.state &= ~QStyle::State_HasFocus;
343
buttonOption.rect.setTopLeft( QPoint( 0, 0 ) );
344
buttonOption.palette = option.palette;
345
buttonOption.features = QStyleOptionButton::None;
348
if ( type == PluginItemDelegate::About ) {
349
if ( m_aboutIcon.isNull() ) {
350
buttonOption.text = tr( "About" );
351
contentSize = buttonOption.fontMetrics.size( 0, buttonOption.text ) + QSize( 4, 4 );
354
buttonOption.icon = m_aboutIcon;
355
buttonOption.iconSize = iconSize;
356
contentSize = iconSize;
359
if ( m_aboutPressedPluginId == index.data( RenderPlugin::NameId ).toString() ) {
360
buttonOption.state |= QStyle::State_Sunken;
363
else if ( type == PluginItemDelegate::Configure ) {
364
if ( m_configIcon.isNull() ) {
365
buttonOption.text = tr( "Configure" );
366
contentSize = buttonOption.fontMetrics.size( 0, buttonOption.text ) + QSize( 4, 4 );
369
buttonOption.icon = m_configIcon;
370
buttonOption.iconSize = iconSize;
371
contentSize = iconSize;
373
if ( m_configPressedPluginId == index.data( RenderPlugin::NameId ).toString() ) {
374
buttonOption.state |= QStyle::State_Sunken;
378
QSize buttonSize = QApplication::style()->sizeFromContents( QStyle::CT_PushButton,
381
buttonOption.rect.setSize( buttonSize );
382
buttonOption.rect = alignRect( buttonOption.rect, option.rect, position, alignment );
386
QSize PluginItemDelegate::nameSize( const QModelIndex& index ) const
388
QString name = index.data( Qt::DisplayRole ).toString();
389
// FIXME: QApplication::fontMetrics() doesn't work for non-application fonts
390
QSize nameSize( QApplication::fontMetrics().size( 0, name ) );
394
QRect PluginItemDelegate::alignRect( QRect object,
397
Qt::AlignmentFlag alignment ) const
401
rect.setTopLeft( QPoint( 0, 0 ) );
402
// Moves the object to the middle of the item.
403
if ( rect.height() < frame.height() ) {
404
rect.moveTop( ( frame.height() - rect.height() ) / 2 );
407
if ( alignment & Qt::AlignLeft ) {
408
rect.moveLeft( position );
410
else if ( alignment & Qt::AlignRight ) {
411
rect.moveRight( position );
418
#include "PluginItemDelegate.moc"