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 Q_UNUSED(end); 00076 // We need to update the rows behind the inserted row as well because the widgets need to be 00077 // moved to their new position 00078 updateRowRange(parent, start, model->rowCount(parent), false); 00079 } 00080 00081 void KWidgetItemDelegatePrivate::_k_slotRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 00082 { 00083 updateRowRange(parent, start, end, true); 00084 } 00085 00086 void KWidgetItemDelegatePrivate::_k_slotRowsRemoved(const QModelIndex &parent, int start, int end) 00087 { 00088 Q_UNUSED(end); 00089 // We need to update the rows that come behind the deleted rows because the widgets need to be 00090 // moved to the new position 00091 updateRowRange(parent, start, model->rowCount(parent), false); 00092 } 00093 00094 void KWidgetItemDelegatePrivate::_k_slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 00095 { 00096 for (int i = topLeft.row(); i <= bottomRight.row(); ++i) { 00097 for (int j = topLeft.column(); j <= bottomRight.column(); ++j) { 00098 const QModelIndex index = model->index(i, j, topLeft.parent()); 00099 QStyleOptionViewItemV4 optionView; 00100 optionView.initFrom(itemView->viewport()); 00101 optionView.rect = itemView->visualRect(index); 00102 widgetPool->findWidgets(index, optionView); 00103 } 00104 } 00105 } 00106 00107 void KWidgetItemDelegatePrivate::_k_slotLayoutChanged() 00108 { 00109 foreach (QWidget *widget, widgetPool->invalidIndexesWidgets()) { 00110 widget->setVisible(false); 00111 } 00112 QTimer::singleShot(0, this, SLOT(initializeModel())); 00113 } 00114 00115 void KWidgetItemDelegatePrivate::_k_slotModelReset() 00116 { 00117 widgetPool->fullClear(); 00118 QTimer::singleShot(0, this, SLOT(initializeModel())); 00119 } 00120 00121 void KWidgetItemDelegatePrivate::updateRowRange(const QModelIndex &parent, int start, int end, bool isRemoving) 00122 { 00123 int i = start; 00124 while (i <= end) { 00125 for (int j = 0; j < model->columnCount(parent); ++j) { 00126 const QModelIndex index = model->index(i, j, parent); 00127 QStyleOptionViewItemV4 optionView; 00128 optionView.initFrom(itemView->viewport()); 00129 optionView.rect = itemView->visualRect(index); 00130 00131 QList<QWidget*> widgetList = widgetPool->findWidgets(index, optionView, isRemoving ? KWidgetItemDelegatePool::NotUpdateWidgets 00132 : KWidgetItemDelegatePool::UpdateWidgets); 00133 if (isRemoving) { 00134 widgetPool->d->allocatedWidgets.removeAll(widgetList); 00135 foreach (QWidget *widget, widgetList) { 00136 const QModelIndex idx = widgetPool->d->widgetInIndex[widget]; 00137 widgetPool->d->usedWidgets.remove(idx); 00138 widgetPool->d->widgetInIndex.remove(widget); 00139 delete widget; 00140 } 00141 } 00142 } 00143 i++; 00144 } 00145 } 00146 00147 void KWidgetItemDelegatePrivate::initializeModel(const QModelIndex &parent) 00148 { 00149 if (!model) { 00150 return; 00151 } 00152 for (int i = 0; i < model->rowCount(parent); ++i) { 00153 for (int j = 0; j < model->columnCount(parent); ++j) { 00154 const QModelIndex index = model->index(i, j, parent); 00155 if (index.isValid()) { 00156 QStyleOptionViewItemV4 optionView; 00157 optionView.initFrom(itemView->viewport()); 00158 optionView.rect = itemView->visualRect(index); 00159 widgetPool->findWidgets(index, optionView); 00160 } 00161 } 00162 // Check if we need to go recursively through the children of parent (if any) to initialize 00163 // all possible indexes that are shown. 00164 const QModelIndex index = model->index(i, 0, parent); 00165 if (index.isValid() && model->hasChildren(index)) { 00166 initializeModel(index); 00167 } 00168 } 00169 } 00170 //@endcond 00171 00172 KWidgetItemDelegate::KWidgetItemDelegate(QAbstractItemView *itemView, QObject *parent) 00173 : QAbstractItemDelegate(parent) 00174 , d(new KWidgetItemDelegatePrivate(this)) 00175 { 00176 Q_ASSERT(itemView); 00177 00178 itemView->setMouseTracking(true); 00179 itemView->viewport()->setAttribute(Qt::WA_Hover); 00180 00181 d->itemView = itemView; 00182 00183 itemView->viewport()->installEventFilter(d); // mouse events 00184 itemView->installEventFilter(d); // keyboard events 00185 00186 if(qobject_cast<QTreeView*>(itemView)) { 00187 connect(itemView, SIGNAL(collapsed(QModelIndex)), 00188 d, SLOT(initializeModel())); 00189 connect(itemView, SIGNAL(expanded(QModelIndex)), 00190 d, SLOT(initializeModel())); 00191 } 00192 } 00193 00194 KWidgetItemDelegate::~KWidgetItemDelegate() 00195 { 00196 delete d; 00197 } 00198 00199 QAbstractItemView *KWidgetItemDelegate::itemView() const 00200 { 00201 return d->itemView; 00202 } 00203 00204 QPersistentModelIndex KWidgetItemDelegate::focusedIndex() const 00205 { 00206 const QPersistentModelIndex idx = d->widgetPool->d->widgetInIndex.value(QApplication::focusWidget()); 00207 if (idx.isValid()) { 00208 return idx; 00209 } 00210 // Use the mouse position, if the widget refused to take keyboard focus. 00211 const QPoint pos = d->itemView->viewport()->mapFromGlobal(QCursor::pos()); 00212 return d->itemView->indexAt(pos); 00213 } 00214 00215 #ifndef KDE_NO_DEPRECATED 00216 void KWidgetItemDelegate::paintWidgets(QPainter *painter, const QStyleOptionViewItem &option, 00217 const QPersistentModelIndex &index) const 00218 { 00219 Q_UNUSED(painter); 00220 Q_UNUSED(option); 00221 Q_UNUSED(index); 00222 } 00223 #endif 00224 00225 //@cond PRIVATE 00226 bool KWidgetItemDelegatePrivate::eventFilter(QObject *watched, QEvent *event) 00227 { 00228 if (event->type() == QEvent::Destroy) { 00229 // we care for the view since it deletes the widgets (parentage). 00230 // if the view hasn't been deleted, it might be that just the 00231 // delegate is removed from it, in which case we need to remove the widgets 00232 // manually, otherwise they still get drawn. 00233 if (watched == itemView) { 00234 viewDestroyed = true; 00235 } 00236 return false; 00237 } 00238 00239 Q_ASSERT(itemView); 00240 00241 if (model != itemView->model()) { 00242 if (model) { 00243 disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), q, SLOT(_k_slotRowsInserted(QModelIndex,int,int))); 00244 disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), q, SLOT(_k_slotRowsAboutToBeRemoved(QModelIndex,int,int))); 00245 disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), q, SLOT(_k_slotRowsRemoved(QModelIndex,int,int))); 00246 disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(_k_slotDataChanged(QModelIndex,QModelIndex))); 00247 disconnect(model, SIGNAL(layoutChanged()), q, SLOT(_k_slotLayoutChanged())); 00248 disconnect(model, SIGNAL(modelReset()), q, SLOT(_k_slotModelReset())); 00249 } 00250 model = itemView->model(); 00251 connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), q, SLOT(_k_slotRowsInserted(QModelIndex,int,int))); 00252 connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), q, SLOT(_k_slotRowsAboutToBeRemoved(QModelIndex,int,int))); 00253 connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), q, SLOT(_k_slotRowsRemoved(QModelIndex,int,int))); 00254 connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(_k_slotDataChanged(QModelIndex,QModelIndex))); 00255 connect(model, SIGNAL(layoutChanged()), q, SLOT(_k_slotLayoutChanged())); 00256 connect(model, SIGNAL(modelReset()), q, SLOT(_k_slotModelReset())); 00257 QTimer::singleShot(0, this, SLOT(initializeModel())); 00258 } 00259 00260 switch (event->type()) { 00261 case QEvent::Polish: 00262 case QEvent::Resize: 00263 if (!qobject_cast<QAbstractItemView*>(watched)) { 00264 QTimer::singleShot(0, this, SLOT(initializeModel())); 00265 } 00266 break; 00267 default: 00268 break; 00269 } 00270 00271 return QObject::eventFilter(watched, event); 00272 } 00273 //@endcond 00274 00275 void KWidgetItemDelegate::setBlockedEventTypes(QWidget *widget, QList<QEvent::Type> types) const 00276 { 00277 widget->setProperty("goya:blockedEventTypes", qVariantFromValue(types)); 00278 } 00279 00280 QList<QEvent::Type> KWidgetItemDelegate::blockedEventTypes(QWidget *widget) const 00281 { 00282 return widget->property("goya:blockedEventTypes").value<QList<QEvent::Type> >(); 00283 } 00284 00285 #include "kwidgetitemdelegate.moc" 00286 #include "kwidgetitemdelegate_p.moc"
KDE 4.7 API Reference