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