krita/ui

kis_categorized_item_delegate.cpp

Go to the documentation of this file.
00001 /*
00002  *  Copyright (c) 2009 Cyrille Berger <cberger@cberger.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU Lesser General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Lesser General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "kis_categorized_item_delegate.h"
00020 
00021 #include <KCategoryDrawer>
00022 #include <KCategorizedSortFilterProxyModel>
00023 #include <QPainter>
00024 
00025 struct KisCategorizedItemDelegate::Private {
00026     QAbstractItemDelegate* fallback;
00027     KCategoryDrawer* categoryDrawer;
00028     bool isFirstOfCategory(const QModelIndex& index);
00029 };
00030 
00031 bool KisCategorizedItemDelegate::Private::isFirstOfCategory(const QModelIndex& index)
00032 {
00033 
00034     if (index.row() == 0) return true;
00035     QModelIndex idx = index.model()->index(index.row() - 1, index.column(), index.parent());
00036     const QString category1 = index.model()->data(index, KCategorizedSortFilterProxyModel::CategorySortRole).toString();
00037     const QString category2 = index.model()->data(idx, KCategorizedSortFilterProxyModel::CategorySortRole).toString();
00038     return category1 != category2;
00039 }
00040 
00041 KisCategorizedItemDelegate::KisCategorizedItemDelegate(QAbstractItemDelegate* _fallback, QObject* parent)
00042         : QAbstractItemDelegate(parent)
00043         , d(new Private)
00044 {
00045     _fallback->setParent(this);
00046     d->fallback = _fallback;
00047     d->categoryDrawer = new KCategoryDrawer;
00048 }
00049 
00050 KisCategorizedItemDelegate::~KisCategorizedItemDelegate()
00051 {
00052 
00053     delete d->fallback;
00054     delete d->categoryDrawer;
00055     delete d;
00056 }
00057 
00058 QWidget * KisCategorizedItemDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
00059 {
00060     return d->fallback->createEditor(parent, option, index);
00061 }
00062 
00063 bool KisCategorizedItemDelegate::editorEvent(QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index)
00064 {
00065     return d->fallback->editorEvent(event, model, option, index);
00066 }
00067 
00068 void KisCategorizedItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & _option, const QModelIndex & index) const
00069 {
00070     // We will need to edit the option to make sure the header isn't drawned as selected
00071     QStyleOptionViewItem* option = 0;
00072     if (const QStyleOptionViewItemV4 *v4 = qstyleoption_cast<const QStyleOptionViewItemV4*>(&_option)) {
00073         option = new QStyleOptionViewItemV4(*v4);
00074     } else if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3*>(&_option)) {
00075         option = new QStyleOptionViewItemV3(*v3);
00076     } else if (const QStyleOptionViewItemV2 *v2 = qstyleoption_cast<const QStyleOptionViewItemV2*>(&_option)) {
00077         option = new QStyleOptionViewItemV2(*v2);
00078     } else {
00079         option = new QStyleOptionViewItem(_option);
00080     }
00081     Q_ASSERT(option);
00082     // If it's a first category then we need to draw it
00083     if (d->isFirstOfCategory(index)) {
00084         // Prepare the rectangle for drawing the category
00085         int h = d->categoryDrawer->categoryHeight(index, *option);
00086         QRect rect = option->rect;
00087 
00088         // Make sure the categroy isn't drawned as selected
00089         option->state &= (~QStyle::State_Selected);
00090         Q_ASSERT(!(option->state & QStyle::State_Selected));
00091         option->state &= (~QStyle::State_HasFocus);
00092         Q_ASSERT(!(option->state & QStyle::State_HasFocus));
00093         option->state &= (~QStyle::State_MouseOver);
00094         Q_ASSERT(!(option->state & QStyle::State_MouseOver));
00095         option->rect.setHeight(h);
00096 
00097         // draw the cateogry
00098         d->categoryDrawer->drawCategory(index, 0, *option, painter);
00099 
00100         // Prepare the rectangle for the item
00101         option->rect = rect;
00102         option->rect.setY(rect.y() + h);
00103         option->rect.setHeight(rect.height() - h);
00104         option->state = _option.state;
00105     }
00106     d->fallback->paint(painter, *option, index);
00107     delete option;
00108 }
00109 
00110 void KisCategorizedItemDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
00111 {
00112     d->fallback->setEditorData(editor, index);
00113 }
00114 
00115 void KisCategorizedItemDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
00116 {
00117     d->fallback->setModelData(editor, model, index);
00118 }
00119 
00120 QSize KisCategorizedItemDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
00121 {
00122     QSize size = d->fallback->sizeHint(option, index);
00123     // If is first of a category, then add the space needed to paint the category
00124     if (d->isFirstOfCategory(index)) {
00125         size.setHeight(d->categoryDrawer->categoryHeight(index, option) + size.height());
00126     }
00127     return size;
00128 }
00129 
00130 void KisCategorizedItemDelegate::updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const
00131 {
00132     d->fallback->updateEditorGeometry(editor, option, index);
00133 
00134     // If it's the first category, then the editor need to be moved
00135     if (d->isFirstOfCategory(index)) {
00136         int h = d->categoryDrawer->categoryHeight(index, option);
00137         editor->move(editor->x(), editor->y() + h);
00138         editor->resize(editor->width(), editor->height() - h);
00139     }
00140 }