KDEUI
kwidgetitemdelegate.cpp
Go to the documentation of this file.
00001 /* 00002 * This file is part of the KDE project 00003 * Copyright (C) 2007-2008 Rafael Fernández López <ereslibre@kde.org> 00004 * Copyright (C) 2008 Kevin Ottens <ervin@kde.org> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Library General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Library General Public License 00017 * along with this library; see the file COPYING.LIB. If not, write to 00018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 */ 00021 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 <QTimer> 00033 #include <QBitmap> 00034 #include <QLayout> 00035 #include <QPainter> 00036 #include <QScrollBar> 00037 #include <QKeyEvent> 00038 #include <QApplication> 00039 #include <QStyleOption> 00040 #include <QPaintEngine> 00041 #include <QCoreApplication> 00042 #include <QAbstractItemView> 00043 #include <QAbstractProxyModel> 00044 #include <QTreeView> 00045 00046 #include "kwidgetitemdelegatepool_p.h" 00047 00048 Q_DECLARE_METATYPE(QList<QEvent::Type>) 00049 00050 00054 //@cond PRIVATE 00055 KWidgetItemDelegatePrivate::KWidgetItemDelegatePrivate(KWidgetItemDelegate *q, QObject *parent) 00056 : QObject(parent) 00057 , itemView(0) 00058 , widgetPool(new KWidgetItemDelegatePool(q)) 00059 , model(0) 00060 , viewDestroyed(false) 00061 , q(q) 00062 { 00063 } 00064 00065 KWidgetItemDelegatePrivate::~KWidgetItemDelegatePrivate() 00066 { 00067 if (!viewDestroyed) { 00068 widgetPool->fullClear(); 00069 } 00070 delete widgetPool; 00071 } 00072 00073 void KWidgetItemDelegatePrivate::_k_slotRowsInserted(const QModelIndex &parent, int start, int end) 00074 { 00075 updateRowRange(parent, start, end, false); 00076 } 00077 00078 void KWidgetItemDelegatePrivate::_k_slotRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 00079 { 00080 updateRowRange(parent, start, end, true); 00081 } 00082 00083 void KWidgetItemDelegatePrivate::_k_slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 00084 { 00085 for (int i = topLeft.row(); i <= bottomRight.row(); ++i) { 00086 for (int j = topLeft.column(); j <= bottomRight.column(); ++j) { 00087 const QModelIndex index = model->index(i, j, topLeft.parent()); 00088 QStyleOptionViewItemV4 optionView; 00089 optionView.initFrom(itemView->viewport()); 00090 optionView.rect = itemView->visualRect(index); 00091 widgetPool->findWidgets(index, optionView); 00092 } 00093 } 00094 } 00095 00096 void KWidgetItemDelegatePrivate::_k_slotLayoutChanged() 00097 { 00098 foreach (QWidget *widget, widgetPool->invalidIndexesWidgets()) { 00099 widget->setVisible(false); 00100 } 00101 QTimer::singleShot(0, this, SLOT(initializeModel())); 00102 } 00103 00104 void KWidgetItemDelegatePrivate::_k_slotModelReset() 00105 { 00106 widgetPool->fullClear(); 00107 QTimer::singleShot(0, this, SLOT(initializeModel())); 00108 } 00109 00110 void KWidgetItemDelegatePrivate::updateRowRange(const QModelIndex &parent, int start, int end, bool isRemoving) 00111 { 00112 int i = start; 00113 while (i <= end) { 00114 for (int j = 0; j < model->columnCount(parent); ++j) { 00115 const QModelIndex index = model->index(i, j, parent); 00116 QStyleOptionViewItemV4 optionView; 00117 optionView.initFrom(itemView->viewport()); 00118 optionView.rect = itemView->visualRect(index); 00119 00120 QList<QWidget*> widgetList = widgetPool->findWidgets(index, optionView, isRemoving ? KWidgetItemDelegatePool::NotUpdateWidgets 00121 : KWidgetItemDelegatePool::UpdateWidgets); 00122 if (isRemoving) { 00123 widgetPool->d->allocatedWidgets.removeAll(widgetList); 00124 foreach (QWidget *widget, widgetList) { 00125 const QModelIndex idx = widgetPool->d->widgetInIndex[widget]; 00126 widgetPool->d->usedWidgets.remove(idx); 00127 widgetPool->d->widgetInIndex.remove(widget); 00128 delete widget; 00129 } 00130 } 00131 } 00132 i++; 00133 } 00134 } 00135 00136 void KWidgetItemDelegatePrivate::initializeModel(const QModelIndex &parent) 00137 { 00138 for (int i = 0; i < model->rowCount(parent); ++i) { 00139 for (int j = 0; j < model->columnCount(parent); ++j) { 00140 const QModelIndex index = model->index(i, j, parent); 00141 if (index.isValid()) { 00142 QStyleOptionViewItemV4 optionView; 00143 optionView.initFrom(itemView->viewport()); 00144 optionView.rect = itemView->visualRect(index); 00145 widgetPool->findWidgets(index, optionView); 00146 } 00147 } 00148 // Check if we need to go recursively through the children of parent (if any) to initialize 00149 // all possible indexes that are shown. 00150 const QModelIndex index = model->index(i, 0, parent); 00151 if (index.isValid() && model->hasChildren(index)) { 00152 initializeModel(index); 00153 } 00154 } 00155 } 00156 //@endcond 00157 00158 KWidgetItemDelegate::KWidgetItemDelegate(QAbstractItemView *itemView, QObject *parent) 00159 : QAbstractItemDelegate(parent) 00160 , d(new KWidgetItemDelegatePrivate(this)) 00161 { 00162 Q_ASSERT(itemView); 00163 00164 itemView->setMouseTracking(true); 00165 itemView->viewport()->setAttribute(Qt::WA_Hover); 00166 00167 d->itemView = itemView; 00168 00169 itemView->viewport()->installEventFilter(d); // mouse events 00170 itemView->installEventFilter(d); // keyboard events 00171 00172 if(qobject_cast<QTreeView*>(itemView)) { 00173 connect(itemView, SIGNAL(collapsed(QModelIndex)), 00174 d, SLOT(initializeModel())); 00175 connect(itemView, SIGNAL(expanded(QModelIndex)), 00176 d, SLOT(initializeModel())); 00177 } 00178 } 00179 00180 KWidgetItemDelegate::~KWidgetItemDelegate() 00181 { 00182 delete d; 00183 } 00184 00185 QAbstractItemView *KWidgetItemDelegate::itemView() const 00186 { 00187 return d->itemView; 00188 } 00189 00190 QPersistentModelIndex KWidgetItemDelegate::focusedIndex() const 00191 { 00192 const QPersistentModelIndex idx = d->widgetPool->d->widgetInIndex.value(QApplication::focusWidget()); 00193 if (idx.isValid()) { 00194 return idx; 00195 } 00196 // Use the mouse position, if the widget refused to take keyboard focus. 00197 const QPoint pos = d->itemView->viewport()->mapFromGlobal(QCursor::pos()); 00198 return d->itemView->indexAt(pos); 00199 } 00200 00201 #ifndef KDE_NO_DEPRECATED 00202 void KWidgetItemDelegate::paintWidgets(QPainter *painter, const QStyleOptionViewItem &option, 00203 const QPersistentModelIndex &index) const 00204 { 00205 Q_UNUSED(painter); 00206 Q_UNUSED(option); 00207 Q_UNUSED(index); 00208 } 00209 #endif 00210 00211 //@cond PRIVATE 00212 bool KWidgetItemDelegatePrivate::eventFilter(QObject *watched, QEvent *event) 00213 { 00214 if (event->type() == QEvent::Destroy) { 00215 // we care for the view since it deletes the widgets (parentage). 00216 // if the view hasn't been deleted, it might be that just the 00217 // delegate is removed from it, in which case we need to remove the widgets 00218 // manually, otherwise they still get drawn. 00219 if (watched == itemView) { 00220 viewDestroyed = true; 00221 } 00222 return false; 00223 } 00224 00225 Q_ASSERT(itemView); 00226 00227 if (model != itemView->model()) { 00228 if (model) { 00229 disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), q, SLOT(_k_slotRowsInserted(QModelIndex,int,int))); 00230 disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), q, SLOT(_k_slotRowsAboutToBeRemoved(QModelIndex,int,int))); 00231 disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(_k_slotDataChanged(QModelIndex,QModelIndex))); 00232 disconnect(model, SIGNAL(layoutChanged()), q, SLOT(_k_slotLayoutChanged())); 00233 disconnect(model, SIGNAL(modelReset()), q, SLOT(_k_slotModelReset())); 00234 } 00235 model = itemView->model(); 00236 connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), q, SLOT(_k_slotRowsInserted(QModelIndex,int,int))); 00237 connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), q, SLOT(_k_slotRowsAboutToBeRemoved(QModelIndex,int,int))); 00238 connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(_k_slotDataChanged(QModelIndex,QModelIndex))); 00239 connect(model, SIGNAL(layoutChanged()), q, SLOT(_k_slotLayoutChanged())); 00240 connect(model, SIGNAL(modelReset()), q, SLOT(_k_slotModelReset())); 00241 QTimer::singleShot(0, this, SLOT(initializeModel())); 00242 } 00243 00244 switch (event->type()) { 00245 case QEvent::Polish: 00246 case QEvent::Resize: 00247 if (!qobject_cast<QAbstractItemView*>(watched)) { 00248 QTimer::singleShot(0, this, SLOT(initializeModel())); 00249 } 00250 break; 00251 default: 00252 break; 00253 } 00254 00255 return QObject::eventFilter(watched, event); 00256 } 00257 //@endcond 00258 00259 void KWidgetItemDelegate::setBlockedEventTypes(QWidget *widget, QList<QEvent::Type> types) const 00260 { 00261 widget->setProperty("goya:blockedEventTypes", qVariantFromValue(types)); 00262 } 00263 00264 QList<QEvent::Type> KWidgetItemDelegate::blockedEventTypes(QWidget *widget) const 00265 { 00266 return widget->property("goya:blockedEventTypes").value<QList<QEvent::Type> >(); 00267 } 00268 00269 #include "kwidgetitemdelegate.moc" 00270 #include "kwidgetitemdelegate_p.moc"
KDE 4.6 API Reference