File indexing completed on 2025-01-05 03:59:31
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2009 Bastian Holst <bastianholst@gmx.de> 0004 // 0005 0006 // Self 0007 #include "PluginItemDelegate.h" 0008 0009 // Qt 0010 #include <QEvent> 0011 #include <QSize> 0012 #include <QVariant> 0013 #include <QAbstractItemView> 0014 #include <QMouseEvent> 0015 #include <QStandardItemModel> 0016 #include <QApplication> 0017 #include <QPainter> 0018 0019 #include <klocalizedstring.h> 0020 0021 // Marble 0022 #include "RenderPluginModel.h" 0023 0024 #include "digikam_debug.h" 0025 0026 using namespace Marble; 0027 0028 const QSize iconSize( 16, 16 ); 0029 0030 PluginItemDelegate::PluginItemDelegate( QAbstractItemView *view, QObject * parent ) 0031 : QAbstractItemDelegate( parent ) 0032 { 0033 // Enable mouse tracking of itemview makes it possible to find when the mouse if moved 0034 // without pressed buttons. 0035 view->setMouseTracking( true ); 0036 } 0037 0038 PluginItemDelegate::~PluginItemDelegate() 0039 { 0040 } 0041 0042 void PluginItemDelegate::paint( QPainter *painter, 0043 const QStyleOptionViewItem& option, 0044 const QModelIndex& index ) const 0045 { 0046 Q_ASSERT( index.isValid() ); 0047 QRect rect = option.rect; 0048 QStyle *style = QApplication::style(); 0049 0050 painter->save(); 0051 0052 // Drawing the background 0053 QStyleOption background = option; 0054 style->drawPrimitive( QStyle::PE_PanelItemViewItem, &option, painter ); 0055 0056 painter->translate( rect.topLeft() ); 0057 0058 // rect is now represented in item coordinates 0059 rect.moveTopLeft( QPoint( 0, 0 ) ); 0060 // The point at the top left of the available drawing area. 0061 QPoint topLeft( 0, 0 ); 0062 // The point at the top right of the available drawing area. 0063 QPoint topRight( rect.topRight() ); 0064 0065 QRect nameRect = rect; 0066 0067 // Painting the checkbox 0068 QStyleOptionButton checkBox = checkboxOption( option, index, topLeft.x(), Qt::AlignLeft ); 0069 painter->save(); 0070 style->drawControl( QStyle::CE_CheckBox, &checkBox, painter ); 0071 painter->restore(); 0072 0073 nameRect.setLeft( checkBox.rect.right() + 1 ); 0074 0075 // Painting the About Button 0076 QStyleOptionButton button = buttonOption( option, index, PluginItemDelegate::About, 0077 topRight.x(), Qt::AlignRight ); 0078 style->drawControl( QStyle::CE_PushButton, &button, painter ); 0079 topRight -= QPoint( button.rect.width(), 0 ); 0080 0081 // Painting the Configure Button 0082 if ( index.data( RenderPluginModel::ConfigurationDialogAvailable ).toBool() ) { 0083 QStyleOptionButton button = buttonOption( option, index, PluginItemDelegate::Configure, 0084 topRight.x(), Qt::AlignRight ); 0085 style->drawControl( QStyle::CE_PushButton, &button, painter ); 0086 topRight -= QPoint( button.rect.width(), 0 ); 0087 0088 nameRect.setRight( button.rect.left() -1 ); 0089 } 0090 0091 // Painting the Icon 0092 const QIcon icon = index.data( Qt::DecorationRole ).value<QIcon>(); 0093 const QPixmap iconPixmap = icon.pixmap(16, 16); 0094 0095 nameRect.moveBottom( nameRect.bottom()+5 ); 0096 style->drawItemPixmap( painter, 0097 nameRect, 0098 Qt::AlignLeft, 0099 iconPixmap ); 0100 0101 nameRect.setLeft( nameRect.left() + 16 + 5 ); 0102 nameRect.moveBottom( nameRect.bottom()-5 ); 0103 0104 // Painting the Name string 0105 QString name = index.data( Qt::DisplayRole ).toString(); 0106 0107 style->drawItemText( painter, 0108 nameRect, 0109 Qt::AlignLeft | Qt::AlignVCenter, 0110 option.palette, 0111 true, 0112 name ); 0113 0114 painter->restore(); 0115 } 0116 0117 QSize PluginItemDelegate::sizeHint( const QStyleOptionViewItem& option, 0118 const QModelIndex & index ) const 0119 { 0120 QSize size; 0121 0122 QStyleOptionViewItem opt = option; 0123 opt.rect = QRect( 0, 0, 0, 0 ); 0124 QVector<QSize> elementSize; 0125 elementSize.reserve(4); 0126 QStyleOptionButton checkBox = checkboxOption( opt, index ); 0127 elementSize.append( checkBox.rect.size() ); 0128 QStyleOptionButton aboutButton = buttonOption( opt, index, PluginItemDelegate::About ); 0129 elementSize.append( aboutButton.rect.size() ); 0130 QStyleOptionButton configButton = buttonOption( opt, index, PluginItemDelegate::Configure ); 0131 elementSize.append( configButton.rect.size() ); 0132 elementSize.append( nameSize( index ) ); 0133 0134 for( const QSize& buttonSize: elementSize ) { 0135 if( buttonSize.height() > size.height() ) 0136 size.setHeight( buttonSize.height() ); 0137 size.setWidth( size.width() + buttonSize.width() ); 0138 } 0139 0140 return size; 0141 } 0142 0143 void PluginItemDelegate::setAboutIcon( const QIcon& icon ) 0144 { 0145 m_aboutIcon = icon; 0146 } 0147 0148 void PluginItemDelegate::setConfigIcon( const QIcon& icon ) 0149 { 0150 m_configIcon = icon; 0151 } 0152 0153 bool PluginItemDelegate::editorEvent( QEvent *event, 0154 QAbstractItemModel *model, 0155 const QStyleOptionViewItem &option, 0156 const QModelIndex &index ) 0157 { 0158 Q_ASSERT(event); 0159 Q_ASSERT(model); 0160 0161 if ( ( event->type() == QEvent::MouseButtonRelease ) 0162 || ( event->type() == QEvent::MouseButtonDblClick ) 0163 || ( event->type() == QEvent::MouseButtonPress ) 0164 || ( event->type() == QEvent::MouseMove ) ) 0165 { 0166 QMouseEvent *me = static_cast<QMouseEvent*>(event); 0167 QPoint mousePosition = me->pos() - option.rect.topLeft(); 0168 0169 if ( ( event->type() == QEvent::MouseMove ) 0170 && !( me->buttons() & Qt::LeftButton ) ) 0171 { 0172 // If the mouse moves around and no left button is pressed, no pushbutton is pressed 0173 // and no other event will be successful. 0174 m_aboutPressedIndex = QModelIndex(); 0175 m_configPressedIndex = QModelIndex(); 0176 return true; 0177 } 0178 0179 // Handle checkbox 0180 QRect checkRect = checkboxOption( option, index, 0, Qt::AlignLeft ).rect; 0181 if ( checkRect.contains( mousePosition ) 0182 && ( ( event->type() == QEvent::MouseButtonDblClick ) 0183 || ( event->type() == QEvent::MouseButtonRelease ) ) ) 0184 { 0185 // make sure that the item is checkable 0186 Qt::ItemFlags flags = model->flags(index); 0187 if ( !( flags & Qt::ItemIsUserCheckable ) || !( option.state & QStyle::State_Enabled ) 0188 || !( flags & Qt::ItemIsEnabled ) ) 0189 return false; 0190 0191 // make sure that we have a check state 0192 QVariant checkValue = index.data( Qt::CheckStateRole ); 0193 if ( !checkValue.isValid() ) 0194 return false; 0195 0196 // eat the double click events inside the check rect 0197 if ( event->type() == QEvent::MouseButtonDblClick ) 0198 return true; 0199 0200 Qt::CheckState state = ( static_cast<Qt::CheckState>( checkValue.toInt() ) == Qt::Checked 0201 ? Qt::Unchecked : Qt::Checked ); 0202 return model->setData(index, state, Qt::CheckStateRole); 0203 } 0204 0205 if ( ( event->type() == QEvent::MouseMove ) 0206 && !( me->buttons() & Qt::LeftButton ) ) 0207 { 0208 m_aboutPressedIndex = QModelIndex(); 0209 m_configPressedIndex = QModelIndex(); 0210 return true; 0211 } 0212 0213 QPoint topRight = option.rect.topRight(); 0214 0215 // Handle aboutButton 0216 { 0217 QRect aboutRect = buttonOption( option, 0218 index, 0219 PluginItemDelegate::About, 0220 topRight.x(), 0221 Qt::AlignRight ).rect; 0222 if ( aboutRect.contains( mousePosition ) ) { 0223 if ( event->type() == QEvent::MouseButtonDblClick ) 0224 return true; 0225 if ( event->type() == QEvent::MouseButtonPress ) { 0226 m_aboutPressedIndex = index; 0227 m_configPressedIndex = QModelIndex(); 0228 return true; 0229 } 0230 if ( event->type() == QEvent::MouseButtonRelease ) { 0231 m_aboutPressedIndex = QModelIndex(); 0232 m_configPressedIndex = QModelIndex(); 0233 Q_EMIT aboutPluginClicked( index ); 0234 return true; 0235 } 0236 if ( event->type() == QEvent::MouseMove ) { 0237 if ( me->buttons() & Qt::LeftButton ) { 0238 m_aboutPressedIndex = index; 0239 m_configPressedIndex = QModelIndex(); 0240 return true; 0241 } 0242 else { 0243 m_aboutPressedIndex = QModelIndex(); 0244 m_configPressedIndex = QModelIndex(); 0245 return true; 0246 } 0247 } 0248 } 0249 else { 0250 // If the mouse is on the item and the mouse isn't above the button. 0251 // no about button is pressed. 0252 m_aboutPressedIndex = QModelIndex(); 0253 } 0254 topRight -= QPoint( aboutRect.width(), 0 ); 0255 } 0256 0257 // Handle configButton 0258 // make sure we have config button 0259 if ( index.data( RenderPluginModel::ConfigurationDialogAvailable ).toBool() ) { 0260 QRect configRect = buttonOption( option, 0261 index, 0262 PluginItemDelegate::Configure, 0263 topRight.x(), 0264 Qt::AlignRight ).rect; 0265 if( configRect.contains( mousePosition ) ) { 0266 if ( event->type() == QEvent::MouseButtonDblClick ) 0267 return true; 0268 0269 if ( event->type() == QEvent::MouseButtonPress ) { 0270 m_aboutPressedIndex = QModelIndex(); 0271 m_configPressedIndex = index; 0272 return true; 0273 } 0274 if ( event->type() == QEvent::MouseButtonRelease ) { 0275 m_aboutPressedIndex = QModelIndex(); 0276 m_configPressedIndex = QModelIndex(); 0277 Q_EMIT configPluginClicked( index ); 0278 return true; 0279 } 0280 if ( event->type() == QEvent::MouseMove ) { 0281 if ( me->buttons() & Qt::LeftButton ) { 0282 m_aboutPressedIndex = QModelIndex(); 0283 m_configPressedIndex = index; 0284 return true; 0285 } 0286 else { 0287 m_aboutPressedIndex = QModelIndex(); 0288 m_configPressedIndex = QModelIndex(); 0289 return true; 0290 } 0291 } 0292 } 0293 else { 0294 // If the mouse is on the item and the mouse isn't above the button. 0295 // no config button is pressed. 0296 m_configPressedIndex = QModelIndex(); 0297 } 0298 0299 topRight -= QPoint( configRect.width(), 0 ); 0300 } 0301 else { 0302 // If we don't have an config dialog shown and the mouse is over this item, 0303 // no config button is pressed. 0304 m_configPressedIndex = QModelIndex(); 0305 } 0306 } 0307 0308 return false; 0309 } 0310 0311 QStyleOptionButton PluginItemDelegate::checkboxOption( const QStyleOptionViewItem& option, 0312 const QModelIndex& index, 0313 int position, 0314 Qt::AlignmentFlag alignment ) 0315 { 0316 QStyleOptionButton styleOptionButton; 0317 if ( index.data( Qt::CheckStateRole ).toBool() ) 0318 styleOptionButton.state = option.state | QStyle::State_On; 0319 else 0320 styleOptionButton.state = option.state | QStyle::State_Off; 0321 QSize size = QApplication::style()->sizeFromContents( QStyle::CT_CheckBox, &option, QSize() ); 0322 if ( size.isEmpty() ) { 0323 // A checkbox has definitely a size != 0 0324 styleOptionButton.rect.setSize( QSize( 22, 22 ) ); 0325 } 0326 else { 0327 styleOptionButton.rect.setSize( QSize( size.width(), size.height() ) ); 0328 } 0329 styleOptionButton.rect = alignRect( styleOptionButton.rect, option.rect, position, alignment ); 0330 return styleOptionButton; 0331 } 0332 0333 QStyleOptionButton PluginItemDelegate::buttonOption( const QStyleOptionViewItem& option, 0334 const QModelIndex& index, 0335 PluginItemDelegate::ButtonType type, 0336 int position, 0337 Qt::AlignmentFlag alignment ) const 0338 { 0339 QStyleOptionButton buttonOption; 0340 buttonOption.state = option.state; 0341 buttonOption.state &= ~QStyle::State_HasFocus; 0342 0343 buttonOption.rect.setTopLeft( QPoint( 0, 0 ) ); 0344 buttonOption.palette = option.palette; 0345 buttonOption.features = QStyleOptionButton::None; 0346 0347 QSize contentSize; 0348 if ( type == PluginItemDelegate::About ) { 0349 if ( m_aboutIcon.isNull() ) { 0350 buttonOption.text = i18n( "About" ); 0351 contentSize = buttonOption.fontMetrics.size( 0, buttonOption.text ) + QSize( 4, 4 ); 0352 } 0353 else { 0354 buttonOption.icon = m_aboutIcon; 0355 buttonOption.iconSize = iconSize; 0356 contentSize = iconSize; 0357 } 0358 0359 if ( m_aboutPressedIndex == index ) { 0360 buttonOption.state |= QStyle::State_Sunken; 0361 } 0362 } 0363 else if ( type == PluginItemDelegate::Configure ) { 0364 if ( m_configIcon.isNull() ) { 0365 buttonOption.text = i18n( "Configure" ); 0366 contentSize = buttonOption.fontMetrics.size( 0, buttonOption.text ) + QSize( 4, 4 ); 0367 } 0368 else { 0369 buttonOption.icon = m_configIcon; 0370 buttonOption.iconSize = iconSize; 0371 contentSize = iconSize; 0372 } 0373 if ( m_configPressedIndex == index ) { 0374 buttonOption.state |= QStyle::State_Sunken; 0375 } 0376 } 0377 0378 QSize buttonSize = QApplication::style()->sizeFromContents( QStyle::CT_PushButton, 0379 &buttonOption, 0380 contentSize ); 0381 buttonOption.rect.setSize( buttonSize ); 0382 buttonOption.rect = alignRect( buttonOption.rect, option.rect, position, alignment ); 0383 return buttonOption; 0384 } 0385 0386 QSize PluginItemDelegate::nameSize( const QModelIndex& index ) 0387 { 0388 QString name = index.data( Qt::DisplayRole ).toString(); 0389 // FIXME: QApplication::fontMetrics() doesn't work for non-application fonts 0390 QSize nameSize( QFontMetrics(qApp->font()).size( 0, name ) ); 0391 return nameSize; 0392 } 0393 0394 QRect PluginItemDelegate::alignRect( const QRect& object, 0395 const QRect& frame, 0396 int position, 0397 Qt::AlignmentFlag alignment ) 0398 { 0399 QRect rect = object; 0400 0401 rect.setTopLeft( QPoint( 0, 0 ) ); 0402 // Moves the object to the middle of the item. 0403 if ( rect.height() < frame.height() ) { 0404 rect.moveTop( ( frame.height() - rect.height() ) / 2 ); 0405 } 0406 0407 if ( alignment & Qt::AlignLeft ) { 0408 rect.moveLeft( position ); 0409 } 0410 else if ( alignment & Qt::AlignRight ) { 0411 rect.moveRight( position ); 0412 } 0413 0414 return rect; 0415 } 0416 0417 0418 #include "moc_PluginItemDelegate.cpp"