Ok, the long awaited config wizard is here (at least in a very basic state). There...
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / gui / qxtitemdelegate.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
4 **
5 ** This file is part of the QxtGui module of the Qt eXTension library
6 **
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
9 ** IBM.
10 **
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
15 **
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
20 **
21 ** <http://libqxt.sourceforge.net>  <foundation@libqxt.org>
22 **
23 ****************************************************************************/
24 #include "qxtitemdelegate.h"
25 #include "qxtitemdelegate_p.h"
26 #include <QApplication>
27 #include <QTreeView>
28 #include <QPainter>
29
30 static const int TOP_LEVEL_EXTENT = 2;
31
32 QxtItemDelegatePrivate::QxtItemDelegatePrivate() :
33         textVisible(true),
34         progressFormat("%1%"),
35         elide(Qt::ElideMiddle),
36         style(Qxt::NoDecoration)
37 {}
38
39 void QxtItemDelegatePrivate::paintButton(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, const QTreeView* view) const
40 {
41     // draw the button
42     QStyleOptionButton buttonOption;
43     buttonOption.state = option.state;
44 #ifdef Q_WS_MAC
45     buttonOption.state |= QStyle::State_Raised;
46 #endif
47     buttonOption.state &= ~QStyle::State_HasFocus;
48     if (view->isExpanded(index))
49         buttonOption.state |= QStyle::State_Sunken;
50     buttonOption.rect = option.rect;
51     buttonOption.palette = option.palette;
52     buttonOption.features = QStyleOptionButton::None;
53     view->style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter, view);
54
55     // draw the branch indicator
56     static const int i = 9;
57     const QRect& r = option.rect;
58     if (index.model()->hasChildren(index))
59     {
60         QStyleOption branchOption;
61         branchOption.initFrom(view);
62         if (branchOption.direction == Qt::LeftToRight)
63             branchOption.rect = QRect(r.left() + i/2, r.top() + (r.height() - i)/2, i, i);
64         else
65             branchOption.rect = QRect(r.right() - i/2 - i, r.top() + (r.height() - i)/2, i, i);
66         branchOption.palette = option.palette;
67         branchOption.state = QStyle::State_Children;
68         if (view->isExpanded(index))
69             branchOption.state |= QStyle::State_Open;
70         view->style()->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, painter, view);
71     }
72
73     // draw the text
74     QRect textrect = QRect(r.left() + i*2, r.top(), r.width() - ((5*i)/2), r.height());
75 #if QT_VERSION < 0x040200
76     QString text = QItemDelegate::elidedText(option.fontMetrics, textrect.width(), elide, index.data().toString());
77 #else // QT_VERSION >= 0x040200
78     QString text = option.fontMetrics.elidedText(index.data().toString(), elide, textrect.width());
79 #endif // QT_VERSION
80     view->style()->drawItemText(painter, textrect, Qt::AlignCenter, option.palette, view->isEnabled(), text);
81 }
82
83 void QxtItemDelegatePrivate::paintMenu(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, const QTreeView* view) const
84 {
85     // draw the menu bar item
86     QStyleOptionMenuItem menuOption;
87     menuOption.palette = view->palette();
88     menuOption.fontMetrics = view->fontMetrics();
89     menuOption.state = QStyle::State_None;
90     // QModelIndex::flags() was introduced in 4.2
91     // => therefore "index.model()->flags(index)"
92     if (view->isEnabled() && index.model()->flags(index) & Qt::ItemIsEnabled)
93         menuOption.state |= QStyle::State_Enabled;
94     else
95         menuOption.palette.setCurrentColorGroup(QPalette::Disabled);
96     menuOption.state |= QStyle::State_Selected;
97     menuOption.state |= QStyle::State_Sunken;
98     menuOption.state |= QStyle::State_HasFocus;
99     menuOption.rect = option.rect;
100     menuOption.text = index.data().toString();
101     menuOption.icon = QIcon(index.data(Qt::DecorationRole).value<QPixmap>());
102     view->style()->drawControl(QStyle::CE_MenuBarItem, &menuOption, painter, view);
103
104     // draw the an arrow as a branch indicator
105     if (index.model()->hasChildren(index))
106     {
107         QStyle::PrimitiveElement arrow;
108         if (view->isExpanded(index))
109             arrow = QStyle::PE_IndicatorArrowUp;
110         else
111             arrow = QStyle::PE_IndicatorArrowDown;
112         static const int i = 9;
113         const QRect& r = option.rect;
114         menuOption.rect = QRect(r.left() + i/2, r.top() + (r.height() - i)/2, i, i);
115         view->style()->drawPrimitive(arrow, &menuOption, painter, view);
116     }
117 }
118
119 void QxtItemDelegatePrivate::paintProgress(QPainter* painter, const QStyleOptionViewItem& option, int progress) const
120 {
121     QStyleOptionProgressBar opt;
122     opt.minimum = 0;
123     opt.maximum = 100;
124     opt.rect = option.rect;
125     opt.progress = progress;
126     opt.textVisible = textVisible;
127     opt.text = progressFormat.arg(progress);
128     QApplication::style()->drawControl(QStyle::CE_ProgressBar, &opt, painter, 0);
129 }
130
131 void QxtItemDelegatePrivate::setCurrentEditor(QWidget* editor, const QModelIndex& index) const
132 {
133     currentEditor = editor;
134     currentEdited = index;
135 }
136
137 void QxtItemDelegatePrivate::closeEditor(QWidget* editor)
138 {
139     if (currentEdited.isValid() && editor == currentEditor)
140     {
141         setCurrentEditor(0, QModelIndex());
142         emit qxt_p().editingFinished(currentEdited);
143     }
144 }
145
146 /*!
147     \class QxtItemDelegate QxtItemDelegate
148     \ingroup QxtGui
149     \brief An extended QItemDelegate with additional signals and optional decoration.
150
151     QxtItemDelegate provides signals for starting and finishing of editing
152     and an optional decoration for top level indices in a QTreeView.
153     QxtItemDelegate can also draw a progress bar for indices providing
154     appropriate progress data.
155  */
156
157 /*!
158     \fn QxtItemDelegate::editingStarted(const QModelIndex& index)
159
160     This signal is emitted after the editing of \a index has been started.
161
162     \sa editingFinished()
163  */
164
165 /*!
166     \fn QxtItemDelegate::editingFinished(const QModelIndex& index)
167
168     This signal is emitted after the editing of \a index has been finished.
169
170     \sa editingStarted()
171  */
172
173 /*!
174     Constructs a new QxtItemDelegate with \a parent.
175  */
176 QxtItemDelegate::QxtItemDelegate(QObject* parent) : QItemDelegate(parent)
177 {
178     QXT_INIT_PRIVATE(QxtItemDelegate);
179     connect(this, SIGNAL(closeEditor(QWidget*)), &qxt_d(), SLOT(closeEditor(QWidget*)));
180 }
181
182 /*!
183     Destructs the item delegate.
184  */
185 QxtItemDelegate::~QxtItemDelegate()
186 {}
187
188 /*!
189     \property QxtItemDelegate::decorationStyle
190     \brief This property holds the top level index decoration style
191
192     Top level indices are decorated according to this property.
193     The default value is \b Qxt::NoDecoration.
194
195     \note The property has effect only in case the delegate is installed
196     on a QTreeView. The view must be the parent of the delegate.
197
198     \note Set \b QTreeView::rootIsDecorated to \b false to avoid
199     multiple branch indicators.
200
201     \sa Qxt::DecorationStyle, QTreeView::rootIsDecorated
202  */
203 Qxt::DecorationStyle QxtItemDelegate::decorationStyle() const
204 {
205     return qxt_d().style;
206 }
207
208 void QxtItemDelegate::setDecorationStyle(Qxt::DecorationStyle style)
209 {
210     qxt_d().style = style;
211 }
212
213 /*!
214     \property QxtItemDelegate::elideMode
215     \brief This property holds the text elide mode
216
217     The text of a decorated top level index is elided according to this property.
218     The default value is \b Qt::ElideMiddle.
219
220     \note The property has effect only for decorated top level indices.
221
222     \sa decorationStyle, Qt::TextElideMode
223  */
224 Qt::TextElideMode QxtItemDelegate::elideMode() const
225 {
226     return qxt_d().elide;
227 }
228
229 void QxtItemDelegate::setElideMode(Qt::TextElideMode mode)
230 {
231     qxt_d().elide = mode;
232 }
233
234 /*!
235     \property QxtItemDelegate::progressTextFormat
236     \brief This property holds the format of optional progress text
237
238     The progress text is formatted according to this property.
239     The default value is \b "%1%".
240
241     \note Progress bar is rendered for indices providing valid
242     numerical data for \b ProgressRole.
243
244         \note \b \%1 is replaced by the progress percent.
245
246     \sa progressTextVisible, ProgressRole
247  */
248 QString QxtItemDelegate::progressTextFormat() const
249 {
250     return qxt_d().progressFormat;
251 }
252
253 void QxtItemDelegate::setProgressTextFormat(const QString& format)
254 {
255     qxt_d().progressFormat = format;
256 }
257
258 /*!
259     \property QxtItemDelegate::progressTextVisible
260     \brief This property holds whether progress text is visible
261
262     The default value is \b true.
263
264     \note Progress bar is rendered for indices providing valid
265     numerical data for \b ProgressRole.
266
267     \sa progressTextFormat, ProgressRole
268  */
269 bool QxtItemDelegate::isProgressTextVisible() const
270 {
271     return qxt_d().textVisible;
272 }
273
274 void QxtItemDelegate::setProgressTextVisible(bool visible)
275 {
276     qxt_d().textVisible = visible;
277 }
278
279 QWidget* QxtItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
280 {
281     QWidget* editor = QItemDelegate::createEditor(parent, option, index);
282     qxt_d().setCurrentEditor(editor, index);
283     emit const_cast<QxtItemDelegate*>(this)->editingStarted(index);
284     return editor;
285 }
286
287 void QxtItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
288 {
289     QItemDelegate::setModelData(editor, model, index);
290     qxt_d().setCurrentEditor(0, QModelIndex());
291     emit const_cast<QxtItemDelegate*>(this)->editingFinished(index);
292 }
293
294 void QxtItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
295 {
296     const QAbstractItemModel* model = index.model();
297     const QTreeView* tree = dynamic_cast<QTreeView*>(parent());
298     const bool topLevel = !index.parent().isValid();
299
300     if (tree && model && topLevel && qxt_d().style != Qxt::NoDecoration)
301     {
302         QStyleOptionViewItem opt;
303         opt.QStyleOption::operator=(option);
304         opt.showDecorationSelected = false;
305
306         QModelIndex valid = model->index(index.row(), 0);
307         QModelIndex sibling = valid;
308         while (sibling.isValid())
309         {
310             opt.rect |= tree->visualRect(sibling);
311             sibling = sibling.sibling(sibling.row(), sibling.column() + 1);
312         }
313
314         switch (qxt_d().style)
315         {
316         case Qxt::Buttonlike:
317             qxt_d().paintButton(painter, opt, valid, tree);
318             break;
319         case Qxt::Menulike:
320             qxt_d().paintMenu(painter, opt, valid, tree);
321             break;
322         default:
323             qWarning("QxtItemDelegate::paint() unknown decoration style");
324             QItemDelegate::paint(painter, opt, valid);
325             break;
326         }
327     }
328     else
329     {
330         QItemDelegate::paint(painter, option, index);
331
332         bool ok = false;
333         const QVariant data = index.data(ProgressRole);
334         const int progress  = data.toInt(&ok);
335         if (data.isValid() && ok)
336             qxt_d().paintProgress(painter, option, progress);
337     }
338 }
339
340 QSize QxtItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
341 {
342     // something slightly bigger for top level indices
343     QSize size = QItemDelegate::sizeHint(option, index);
344     if (!index.parent().isValid())
345         size += QSize(TOP_LEVEL_EXTENT, TOP_LEVEL_EXTENT);
346     return  size;
347 }