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
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
00073
00074
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) {
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
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 ¤tIndex,
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
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);
00210 itemView->installEventFilter(d);
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
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
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
00259
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
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
00324
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
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
00419
00420
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
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"