27#include <QApplication>
30class KExtendableItemDelegate::Private {
42 void _k_extenderDestructionHandler(QObject *destroyed);
43 void _k_verticalScroll();
45 QSize maybeExtendedSize(
const QStyleOptionViewItem &option,
const QModelIndex &index)
const;
46 QModelIndex indexOfExtendedColumnInSameRow(
const QModelIndex &index)
const;
47 void scheduleUpdateViewLayout();
54 void deleteExtenders();
57 QHash<QPersistentModelIndex, QWidget *> extenders;
58 QHash<QWidget *, QPersistentModelIndex> extenderIndices;
59 QHash<QWidget *, QPersistentModelIndex> deletionQueue;
61 QPixmap contractPixmap;
65 QModelIndex cachedParentIndex;
72 : QStyledItemDelegate(parent),
75 connect(parent->verticalScrollBar(), SIGNAL(valueChanged(
int)),
76 this, SLOT(_k_verticalScroll()));
90 if (!ext || !index.isValid()) {
98 QAbstractItemView *aiv = qobject_cast<QAbstractItemView *>(parent());
102 ext->setParent(aiv->viewport());
103 d->extenders.insert(index, ext);
104 d->extenderIndices.insert(ext, index);
105 connect(ext, SIGNAL(destroyed(
QObject*)),
this, SLOT(_k_extenderDestructionHandler(
QObject*)));
107 d->scheduleUpdateViewLayout();
113 QWidget *extender = d->extenders.value(index);
119 extender->deleteLater();
121 QPersistentModelIndex persistentIndex = d->extenderIndices.take(extender);
122 d->extenders.remove(persistentIndex);
124 d->deletionQueue.insert(extender, persistentIndex);
126 d->scheduleUpdateViewLayout();
132 d->deleteExtenders();
137void KExtendableItemDelegate::Private::_k_extenderDestructionHandler(
QObject *destroyed)
144 QPersistentModelIndex persistentIndex = deletionQueue.take(extender);
145 if (persistentIndex.isValid() &&
148 QModelIndex index = persistentIndex;
152 scheduleUpdateViewLayout();
157void KExtendableItemDelegate::Private::_k_verticalScroll()
159 foreach (QWidget *extender, extenders) {
174 return d->extenders.value(index);
182 if (!d->extenders.isEmpty()) {
183 ret = d->maybeExtendedSize(option, index);
185 ret = QStyledItemDelegate::sizeHint(option, index);
188 bool showExtensionIndicator = index.model() ?
190 if (showExtensionIndicator) {
191 ret.rwidth() += d->extendPixmap.width();
203 QStyleOptionViewItemV4 indicatorOption(option);
204 initStyleOption(&indicatorOption, index);
205 if (index.column() == 0) {
206 indicatorOption.viewItemPosition = QStyleOptionViewItemV4::Beginning;
207 }
else if (index.column() == index.model()->columnCount() - 1) {
208 indicatorOption.viewItemPosition = QStyleOptionViewItemV4::End;
210 indicatorOption.viewItemPosition = QStyleOptionViewItemV4::Middle;
213 QStyleOptionViewItemV4 itemOption(option);
214 initStyleOption(&itemOption, index);
215 if (index.column() == 0) {
216 itemOption.viewItemPosition = QStyleOptionViewItemV4::Beginning;
217 }
else if (index.column() == index.model()->columnCount() - 1) {
218 itemOption.viewItemPosition = QStyleOptionViewItemV4::End;
220 itemOption.viewItemPosition = QStyleOptionViewItemV4::Middle;
225 if (showExtensionIndicator) {
226 if (QApplication::isRightToLeft()) {
227 indicatorX = option.rect.right() - d->extendPixmap.width();
228 itemOption.rect.setRight(option.rect.right() - d->extendPixmap.width());
229 indicatorOption.rect.setLeft(option.rect.right() - d->extendPixmap.width());
231 indicatorX = option.rect.left();
232 indicatorOption.rect.setRight(option.rect.left() + d->extendPixmap.width());
233 itemOption.rect.setLeft(option.rect.left() + d->extendPixmap.width());
235 indicatorY = option.rect.top() + ((option.rect.height() - d->extendPixmap.height()) >> 1);
239 if (d->extenders.isEmpty()) {
240 QStyledItemDelegate::paint(painter, itemOption, index);
241 if (showExtensionIndicator) {
243 QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &indicatorOption,
246 painter->drawPixmap(indicatorX, indicatorY, d->extendPixmap);
251 int row = index.row();
252 QModelIndex parentIndex = index.parent();
255 if (row != d->cachedRow || d->cachedStateTick != d->stateTick
256 || d->cachedParentIndex != parentIndex) {
257 d->extender = d->extenders.value(d->indexOfExtendedColumnInSameRow(index));
258 d->cachedStateTick = d->stateTick;
260 d->cachedParentIndex = parentIndex;
262 d->extenderHeight = d->extender->sizeHint().height();
267 QStyledItemDelegate::paint(painter, itemOption, index);
268 if (showExtensionIndicator) {
270 QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &indicatorOption,
273 painter->drawPixmap(indicatorX, indicatorY, d->extendPixmap);
280 QStyleOptionViewItemV4 extOption(option);
281 initStyleOption(&extOption, index);
282 extOption.rect =
extenderRect(d->extender, option, index);
289 indicatorOption.rect.setHeight(option.rect.height() - d->extenderHeight);
290 itemOption.rect.setHeight(option.rect.height() - d->extenderHeight);
294 QStyledItemDelegate::paint(painter, itemOption, index);
296 if (showExtensionIndicator) {
298 indicatorY = indicatorOption.rect.top() + ((indicatorOption.rect.height() -
299 d->extendPixmap.height()) >> 1);
301 QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &indicatorOption,
305 if (d->extenders.contains(index)) {
306 painter->drawPixmap(indicatorX, indicatorY, d->contractPixmap);
308 painter->drawPixmap(indicatorX, indicatorY, d->extendPixmap);
317 QRect rect(option.rect);
318 rect.setTop(rect.bottom() + 1 - extender->sizeHint().height());
321 if (QTreeView *tv = qobject_cast<QTreeView *>(parent())) {
323 for (QModelIndex idx(index.parent()); idx.isValid(); idx = idx.parent()) {
326 if (tv->rootIsDecorated()) {
329 indentation = indentSteps * tv->indentation();
332 QAbstractScrollArea *container = qobject_cast<QAbstractScrollArea *>(parent());
334 if (qApp->isLeftToRight()) {
335 rect.setLeft(indentation);
336 rect.setRight(container->viewport()->width() - 1);
338 rect.setRight(container->viewport()->width() - 1 - indentation);
345QSize KExtendableItemDelegate::Private::maybeExtendedSize(
const QStyleOptionViewItem &option,
const QModelIndex &index)
const
347 QWidget *extender = extenders.value(index);
348 QSize size(q->QStyledItemDelegate::sizeHint(option, index));
353 int itemHeight = size.height();
355 int row = index.row();
356 int thisColumn = index.column();
359 for (
int column = 0; index.model()->columnCount() < column; column++) {
360 if (column == thisColumn) {
363 QModelIndex neighborIndex(index.sibling(row, column));
364 if (!neighborIndex.isValid()) {
367 itemHeight = qMax(itemHeight, q->QStyledItemDelegate::sizeHint(option, neighborIndex).height());
371 size.rheight() = itemHeight + extender->sizeHint().height();
376QModelIndex KExtendableItemDelegate::Private::indexOfExtendedColumnInSameRow(
const QModelIndex &index)
const
378 const QAbstractItemModel *
const model = index.model();
379 const QModelIndex parentIndex(index.parent());
380 const int row = index.row();
381 const int columnCount = model->columnCount();
384 for (
int column = 0; column < columnCount; column++) {
385 QModelIndex indexOfExt(model->index(row, column, parentIndex));
386 if (extenders.value(indexOfExt)) {
391 return QModelIndex();
396 const QModelIndex &index)
const
399 extender->setGeometry(option.rect);
403void KExtendableItemDelegate::Private::deleteExtenders()
405 foreach (
QWidget *ext, extenders) {
409 deletionQueue.unite(extenderIndices);
411 extenderIndices.clear();
417void KExtendableItemDelegate::Private::scheduleUpdateViewLayout()
419 QAbstractItemView *aiv = qobject_cast<QAbstractItemView *>(q->parent());
423 aiv->setRootIndex(aiv->rootIndex());
430 d->extendPixmap = pixmap;
436 d->contractPixmap = pixmap;
442 return d->extendPixmap;
448 return d->contractPixmap;
451#include "kextendableitemdelegate.moc"
QPixmap contractPixmap()
Return the pixmap that is displayed to contract an item.
void contractItem(const QModelIndex &index)
Remove the extender of item at index from the view.
void contractAll()
Close all extenders and delete all extender widgets.
QPixmap extendPixmap()
Return the pixmap that is displayed to extend an item.
void setExtendPixmap(const QPixmap &pixmap)
The pixmap that is displayed to extend an item.
void setContractPixmap(const QPixmap &pixmap)
The pixmap that is displayed to contract an item.
virtual ~KExtendableItemDelegate()
QRect extenderRect(QWidget *extender, const QStyleOptionViewItem &option, const QModelIndex &index) const
Reimplement this function to fine-tune the position of the extender.
bool isExtended(const QModelIndex &index) const
Return whether there is an extender that belongs to index.
KExtendableItemDelegate(QAbstractItemView *parent)
Create a new KExtendableItemDelegate that belongs to parent.
virtual void updateExtenderGeometry(QWidget *extender, const QStyleOptionViewItem &option, const QModelIndex &index) const
Reimplement this function to adjust the internal geometry of the extender.
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
Re-implemented for internal reasons.
void extendItem(QWidget *extender, const QModelIndex &index)
Insert the extender for item at index into the view.
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
Re-implemented for internal reasons.
@ ShowExtensionIndicatorRole
void extenderDestroyed(QWidget *extender, const QModelIndex &index)
This signal indicates that the extender belonging to index has emitted the destroyed() signal.
void extenderCreated(QWidget *extender, const QModelIndex &index)
This signal indicates that the item at index was extended with extender.