• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

kwidgetitemdelegate.cpp

Go to the documentation of this file.
00001 
00022 #include "kwidgetitemdelegate.h"
00023 #include "kwidgetitemdelegate_p.h"
00024 
00025 #include <QIcon>
00026 #include <QSize>
00027 #include <QStyle>
00028 #include <QEvent>
00029 #include <QHoverEvent>
00030 #include <QFocusEvent>
00031 #include <QCursor>
00032 #include <QBitmap>
00033 #include <QLayout>
00034 #include <QPainter>
00035 #include <QScrollBar>
00036 #include <QKeyEvent>
00037 #include <QStyleOption>
00038 #include <QPaintEngine>
00039 #include <QCoreApplication>
00040 #include <QAbstractItemView>
00041 
00042 #include "kwidgetitemdelegatepool_p.h"
00043 
00044 Q_DECLARE_METATYPE(QList<QEvent::Type>)
00045 
00046 
00050 //@cond PRIVATE
00051 KWidgetItemDelegatePrivate::KWidgetItemDelegatePrivate(KWidgetItemDelegate *q, QObject *parent)
00052     : QObject(parent)
00053     , itemView(0)
00054     , hoveredIndex(QPersistentModelIndex())
00055     , lastHoveredIndex(QPersistentModelIndex())
00056     , hoveredWidget(0)
00057     , focusedIndex(QPersistentModelIndex())
00058     , focusedWidget(0)
00059     , buttonPressedWidget(0)
00060     , currentIndex(QPersistentModelIndex())
00061     , selectionModel(0)
00062     , widgetPool(new KWidgetItemDelegatePool(q))
00063     , q(q)
00064 {
00065 }
00066 
00067 KWidgetItemDelegatePrivate::~KWidgetItemDelegatePrivate()
00068 {
00069     delete widgetPool;
00070 }
00071 
00072 // When receiving move events on the viewport we need to check if we should
00073 // post events to certain widgets like "enter", "leave"...
00074 // Note: mouseEvent can be 0
00075 void KWidgetItemDelegatePrivate::analyzeInternalMouseEvents(const QStyleOptionViewItem &option,
00076                                                             QMouseEvent *mouseEvent)
00077 {
00078     QPoint pos;
00079     if (mouseEvent) {
00080         pos = mouseEvent->globalPos();
00081     } else {
00082         pos = QCursor::pos();
00083     }
00084 
00085     QRect mappedRect;
00086 
00087     if (hoveredWidget) {
00088         mappedRect = QRect(itemView->viewport()->mapToGlobal(widgetRect(hoveredWidget, option, hoveredIndex).topLeft()),
00089                            itemView->viewport()->mapToGlobal(widgetRect(hoveredWidget, option, hoveredIndex).bottomRight()));
00090     }
00091 
00092     QRect globalViewPortRect(itemView->viewport()->mapToGlobal(itemView->viewport()->rect().topLeft()),
00093                              itemView->viewport()->mapToGlobal(itemView->viewport()->rect().bottomRight()));
00094     bool itemViewContainsMousePos = globalViewPortRect.contains(pos);
00095 
00096     if (hoveredWidget && (!mappedRect.contains(pos) || !itemViewContainsMousePos)) {
00097         QPersistentModelIndex indexList[] = { lastHoveredIndex, hoveredIndex };
00098         for (int i = 0; i < 2; i++) {
00099             if (!indexList[i].isValid()) {
00100                 continue;
00101             }
00102 
00103             QEvent leaveEvent(QEvent::Leave);
00104             QCoreApplication::sendEvent(hoveredWidget, &leaveEvent);
00105             if (mouseEvent) {
00106                 QHoverEvent hoverLeaveEvent(QEvent::HoverLeave,
00107                                             mappedPointForWidget(hoveredWidget, indexList[i], mouseEvent->pos()),
00108                                             mappedPointForWidget(hoveredWidget, indexList[i], mouseEvent->pos()));
00109                 QCoreApplication::sendEvent(hoveredWidget, &hoverLeaveEvent);
00110             }
00111         }
00112 
00113         hoveredWidget = 0;
00114 
00115         return;
00116     }
00117 
00118     if (!itemViewContainsMousePos) {
00119         return;
00120     }
00121 
00122     QList<QWidget*> widgetList = widgetPool->findWidgets(hoveredIndex, option);
00123 
00124     foreach (QWidget *widget, widgetList) {
00125         if (!widget->isVisibleTo(widget->parentWidget())) continue;
00126 
00127         QWidget *childWidget = widget;
00128         if (mouseEvent) {
00129             QPoint eventPos = mappedPointForWidget(widget, hoveredIndex, mouseEvent->pos());
00130             childWidget = widget->childAt(eventPos);
00131 
00132             if (!childWidget) {
00133                 childWidget = widget;
00134             }
00135         }
00136 
00137         if (widget != hoveredWidget || hoveredWidget != childWidget) {
00138             QRect mappedRect = QRect(itemView->viewport()->mapToGlobal(widgetRect(widget, option, hoveredIndex).topLeft()),
00139                                      itemView->viewport()->mapToGlobal(widgetRect(widget, option, hoveredIndex).bottomRight()));
00140 
00141             if (mappedRect.contains(pos)) {
00142                 hoveredWidget = childWidget;
00143 
00144                 QEvent enterEvent(QEvent::Enter);
00145                 QCoreApplication::sendEvent(hoveredWidget, &enterEvent);
00146                 if (mouseEvent) {
00147                     QHoverEvent hoverEnterEvent(QEvent::HoverEnter,
00148                                                 mappedPointForWidget(hoveredWidget, hoveredIndex, mouseEvent->pos()),
00149                                                 mappedPointForWidget(hoveredWidget, hoveredIndex, mouseEvent->pos()));
00150                     QCoreApplication::sendEvent(hoveredWidget, &hoverEnterEvent);
00151                 }
00152                 break;
00153             }
00154         } else if (mouseEvent) { // we are moving the mouse over a previously hovered widget, generate MouseMove events
00155             QPoint eventPos = mappedPointForWidget(childWidget, hoveredIndex, mouseEvent->pos());
00156             QMouseEvent genMouseEvent(QEvent::MouseMove, eventPos, pos, mouseEvent->button(),
00157                                       mouseEvent->buttons(), mouseEvent->modifiers());
00158             QCoreApplication::sendEvent(hoveredWidget, &genMouseEvent);
00159             QHoverEvent hoverMoveEvent(QEvent::HoverMove,
00160                                        mappedPointForWidget(hoveredWidget, hoveredIndex, mouseEvent->pos()),
00161                                        mappedPointForWidget(hoveredWidget, hoveredIndex, mouseEvent->pos()));
00162             QCoreApplication::sendEvent(hoveredWidget, &hoverMoveEvent);
00163             break;
00164         }
00165     }
00166 }
00167 
00168 QPoint KWidgetItemDelegatePrivate::mappedPointForWidget(QWidget *widget,
00169                                                         const QPersistentModelIndex &index,
00170                                                         const QPoint &pos) const
00171 {
00172     // Map the event point relative to the widget
00173     QStyleOptionViewItem option;
00174     option.rect = itemView->visualRect(index);
00175     QPoint widgetPos = widget->pos();
00176     widgetPos.setX(widgetPos.x() + option.rect.left());
00177     widgetPos.setY(widgetPos.y() + option.rect.top());
00178 
00179     return pos - widgetPos;
00180 }
00181 
00182 void KWidgetItemDelegatePrivate::slotCurrentChanged(const QModelIndex &currentIndex,
00183                                                     const QModelIndex &previousIndex)
00184 {
00185     Q_UNUSED(previousIndex);
00186 
00187     this->currentIndex = currentIndex;
00188 
00189     itemView->viewport()->update();
00190 }
00191 
00192 void KWidgetItemDelegatePrivate::slotSelectionModelDestroyed()
00193 {
00194     selectionModel = 0;
00195 }
00196 //@endcond
00197 
00198 KWidgetItemDelegate::KWidgetItemDelegate(QAbstractItemView *itemView, QObject *parent)
00199     : QAbstractItemDelegate(parent)
00200     , d(new KWidgetItemDelegatePrivate(this))
00201 {
00202     Q_ASSERT(itemView);
00203 
00204     itemView->setMouseTracking(true);
00205     itemView->viewport()->setAttribute(Qt::WA_Hover);
00206 
00207     d->itemView = itemView;
00208 
00209     itemView->viewport()->installEventFilter(d); // mouse events
00210     itemView->installEventFilter(d);             // keyboard events
00211 
00212     if (itemView->selectionModel()) {
00213         d->selectionModel = itemView->selectionModel();
00214 
00215         connect(itemView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00216                 d, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)));
00217     }
00218 }
00219 
00220 KWidgetItemDelegate::~KWidgetItemDelegate()
00221 {
00222     delete d;
00223 }
00224 
00225 QAbstractItemView *KWidgetItemDelegate::itemView() const
00226 {
00227     return d->itemView;
00228 }
00229 
00230 QPersistentModelIndex KWidgetItemDelegate::focusedIndex() const
00231 {
00232     return d->focusedIndex;
00233 }
00234 
00235 //@cond PRIVATE
00236 QRect KWidgetItemDelegatePrivate::widgetRect(QWidget *widget,
00237                                              const QStyleOptionViewItem &option,
00238                                              const QPersistentModelIndex &index) const
00239 {
00240     Q_UNUSED(index);
00241     QRect retRect = QRect(widget->pos(), widget->size());
00242     retRect.translate(option.rect.topLeft());
00243     return retRect;
00244 }
00245 //@endcond
00246 
00247 void KWidgetItemDelegate::paintWidgets(QPainter *painter, const QStyleOptionViewItem &option,
00248                                        const QPersistentModelIndex &index) const
00249 {
00250     if (!index.isValid()) {
00251         return;
00252     }
00253 
00254     Q_ASSERT(d->itemView);
00255 
00256     QList<QWidget*> widgetList = d->widgetPool->findWidgets(index, option);
00257 
00258     // Now that all widgets have been set up we can ask for their positions, sizes
00259     // and for them being rendered.
00260     foreach (QWidget *widget, widgetList) {
00261         if (!widget->isVisibleTo(widget->parentWidget())) continue;
00262 
00263         QPoint widgetPos = widget->pos();
00264         QSize widgetSize = widget->size();
00265 
00266         QPixmap pixmap(widgetSize.width(), widgetSize.height());
00267         pixmap.fill(QColor(Qt::transparent));
00268 
00269         widget->render(&pixmap, QPoint(0, 0),
00270                        QRect(QPoint(0, 0), widgetSize),
00271                        QWidget::DrawChildren);
00272         painter->drawPixmap(widgetPos + option.rect.topLeft(), pixmap);
00273     }
00274 }
00275 
00276 //@cond PRIVATE
00277 bool KWidgetItemDelegatePrivate::eventFilter(QObject *watched, QEvent *event)
00278 {
00279     if (event->type() == QEvent::Destroy) {
00280         return false;
00281     }
00282 
00283     Q_UNUSED(watched);
00284     Q_ASSERT(itemView);
00285 
00286     if (selectionModel != itemView->selectionModel()) {
00287         if (selectionModel) {
00288             disconnect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00289                        this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)));
00290         }
00291 
00292         selectionModel = itemView->selectionModel();
00293 
00294         if (selectionModel) {
00295             connect(selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00296                     this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)));
00297             connect(selectionModel, SIGNAL(destroyed(QObject*)),
00298                     this, SLOT(slotSelectionModelDestroyed()));
00299         }
00300     }
00301 
00302     bool filterEvent = false;
00303     bool eventReply = false;
00304 
00305     switch (event->type()) {
00306         case QEvent::Paint:
00307         case QEvent::Timer:
00308         case QEvent::UpdateRequest:
00309         case QEvent::Destroy:
00310         case QEvent::MetaCall:
00311             return false;
00312         case QEvent::Leave:
00313         case QEvent::Enter:
00314         case QEvent::MouseMove: {
00315                 QStyleOptionViewItem styleOptionViewItem;
00316                 styleOptionViewItem.initFrom(itemView);
00317                 styleOptionViewItem.rect = itemView->visualRect(hoveredIndex);
00318 
00319                 QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event);
00320                 lastHoveredIndex = hoveredIndex;
00321                 hoveredIndex = itemView->indexAt(itemView->viewport()->mapFromGlobal(QCursor::pos()));
00322 
00323                 // If a widget has been pressed and not released, mouse move events will be forwarded to the
00324                 // initially pressed widget (until the button mouse is released).
00325                 if (buttonPressedWidget) {
00326                     if (event->type() == QEvent::MouseMove) {
00327                         hoveredWidget = buttonPressedWidget;
00328 
00329                         QMouseEvent mouseEventCpy(mouseEvent->type(), mappedPointForWidget(hoveredWidget, buttonPressedIndex, mouseEvent->pos()),
00330                                                   mouseEvent->globalPos(), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers());
00331 
00332                         QCoreApplication::sendEvent(hoveredWidget, &mouseEventCpy);
00333                     }
00334                 } else {
00335                     // Consider moving this block into analyzeInternalMouseEvents
00336                     if (hoveredWidget && lastHoveredIndex.isValid() && (hoveredIndex != lastHoveredIndex)) {
00337                         QEvent leaveEvent(QEvent::Leave);
00338                         QCoreApplication::sendEvent(hoveredWidget, &leaveEvent);
00339                     }
00340 
00341                     if (event->type() == QEvent::Leave && !buttonPressedWidget) {
00342                         QStyleOptionViewItem option;
00343                         option.rect = itemView->visualRect(hoveredIndex);
00344                         analyzeInternalMouseEvents(option, 0);
00345                     } else {
00346                         QStyleOptionViewItem option;
00347                         option.rect = itemView->visualRect(hoveredIndex);
00348                         analyzeInternalMouseEvents(option, mouseEvent);
00349                     }
00350                 }
00351 
00352                 itemView->viewport()->update();
00353 
00354                 if (hoveredWidget) {
00355                     itemView->setCursor(hoveredWidget->cursor());
00356                 } else {
00357                     itemView->setCursor(Qt::ArrowCursor);
00358                 }
00359             }
00360             break;
00361         case QEvent::MouseButtonPress:
00362         case QEvent::MouseButtonRelease: {
00363                 focusedIndex = hoveredIndex;
00364 
00365                 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
00366 
00367                 if (event->type() == QEvent::MouseButtonPress) {
00368                     buttonPressedWidget = hoveredWidget;
00369                     buttonPressedIndex = hoveredIndex;
00370                 } else {
00371                     buttonPressedWidget = 0;
00372                     buttonPressedIndex = QModelIndex();
00373                 }
00374 
00375                 if (focusedWidget && (focusedWidget != hoveredWidget)) {
00376 
00377                     QFocusEvent focusEvent(QEvent::FocusOut);
00378                     QCoreApplication::sendEvent(focusedWidget, &focusEvent);
00379                 }
00380 
00381                 if (hoveredWidget) {
00382                     QPoint eventPos = mappedPointForWidget(hoveredWidget,
00383                                                            hoveredIndex,
00384                                                            mouseEvent->pos());
00385 
00386                     QMouseEvent mouseEvt(mouseEvent->type(), eventPos, mouseEvent->button(),
00387                                          mouseEvent->buttons(), mouseEvent->modifiers());
00388 
00389                     QWidget *receiver = hoveredWidget;
00390 
00391                     QWidget *parent = hoveredWidget->parentWidget();
00392                     QPoint itemPos = itemView->visualRect(hoveredIndex).topLeft();
00393                     QPoint globalPos = itemView->viewport()->mapToGlobal(itemPos);
00394                     parent->move(globalPos);
00395                     parent->resize(itemView->visualRect(hoveredIndex).size());
00396 
00397                     QCoreApplication::sendEvent(hoveredWidget, &mouseEvt);
00398 
00399                     QList<QEvent::Type> blocked = q->blockedEventTypes(receiver);
00400                     filterEvent = blocked.contains(mouseEvent->type());
00401 
00402                     focusedWidget = receiver;
00403 
00404                     QFocusEvent focusEvent(QEvent::FocusIn);
00405                     QCoreApplication::sendEvent(focusedWidget, &focusEvent);
00406                 } else {
00407                     focusedWidget = 0;
00408                 }
00409             }
00410             itemView->viewport()->update();
00411             break;
00412         default: {
00413                 if (event->type() == QEvent::FocusOut) {
00414                     buttonPressedWidget = 0;
00415                     buttonPressedIndex = QModelIndex();
00416                 }
00417 
00418                 // We don't need to do special stuff with this events. Just forward them the best we can
00419                 // at this point. If it is a key event, send it to the focused widget (if any), and in other
00420                 // case, forward it to the hovered widget (if any).
00421                 if (dynamic_cast<QKeyEvent*>(event) && focusedWidget) {
00422                     QCoreApplication::sendEvent(focusedWidget, event);
00423                     QList<QEvent::Type> blocked = q->blockedEventTypes(focusedWidget);
00424                     filterEvent = blocked.contains(event->type());
00425                 } else if (hoveredWidget) {
00426                     QCoreApplication::sendEvent(hoveredWidget, event);
00427                     QList<QEvent::Type> blocked = q->blockedEventTypes(hoveredWidget);
00428                     filterEvent = blocked.contains(event->type());
00429                 }
00430             }
00431             itemView->viewport()->update();
00432             break;
00433     }
00434 
00435     return filterEvent || eventReply;
00436 }
00437 //@endcond
00438 
00439 void KWidgetItemDelegate::setBlockedEventTypes(QWidget *widget, QList<QEvent::Type> types) const
00440 {
00441     widget->setProperty("goya:blockedEventTypes", qVariantFromValue(types));
00442 }
00443 
00444 QList<QEvent::Type> KWidgetItemDelegate::blockedEventTypes(QWidget *widget) const
00445 {
00446     return widget->property("goya:blockedEventTypes").value<QList<QEvent::Type> >();
00447 }
00448 
00449 #include "kwidgetitemdelegate_p.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal