Vidalia 0.3.1
StatusEventItemDelegate.cpp
Go to the documentation of this file.
1/*
2** This file is part of Vidalia, and is subject to the license terms in the
3** LICENSE file, found in the top level directory of this distribution. If you
4** did not receive the LICENSE file with this file, you may obtain it from the
5** Vidalia source package distributed by the Vidalia Project at
6** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7** including this file, may be copied, modified, propagated, or distributed
8** except according to the terms described in the LICENSE file.
9*/
10
11/*
12** \file StatusEventItemDelegate.cpp
13** \brief Handles custom painting of items in a StatusEventWidget
14*/
15
17#include "StatusEventItem.h"
18
19#include "Vidalia.h"
20
21#include <QPainter>
22#include <QTextLine>
23#include <QTextLayout>
24
26 : QItemDelegate(parent)
27{
28 _helpIcon = QPixmap(":/images/16x16/system-help.png");
29}
30
31void
33 const QStyleOptionViewItem &option,
34 const QModelIndex &index) const
35{
36 QItemDelegate::paint(painter, option, index);
37
38 painter->save();
39 if (option.state & QStyle::State_Selected)
40 painter->setPen(option.palette.highlightedText().color());
41
42 QPixmap icon = index.data(StatusEventItem::IconRole).value<QPixmap>();
43 QTime tstamp = index.data(StatusEventItem::TimestampRole).toTime();
44 QString title = index.data(StatusEventItem::TitleRole).toString();
45 QString text = index.data(StatusEventItem::DescriptionRole).toString();
46 QFont font = option.font;
47 QFontMetrics fm = option.fontMetrics;
48
49 /* XXX: Handle right-to-left layouts here. */
50 QRect iconRect(option.rect.x(),
51 option.rect.y(),
52 qMax(fm.width(tstamp.toString()), icon.width()) + 16,
53 option.rect.height());
54 QRect textRect(iconRect.topRight(), option.rect.bottomRight());
55
56 // Draw the status icon
57 QPoint center = iconRect.center();
58 int x = center.x() - qRound(icon.width() / 2.0);
59 int y = center.y() - qRound((icon.height() + fm.lineSpacing()) / 2.0);
60 painter->drawPixmap(x, y, icon);
61
62 // Draw the timestamp text underneath the status icon
63 x = iconRect.x();
64 y = y + icon.height();
65 painter->drawText(x, y,
66 iconRect.width(),
67 fm.lineSpacing(),
68 Qt::AlignCenter,
69 tstamp.toString());
70
71 // Draw the event's title in a bold font. If the current item has an
72 // associated help URL, draw the little "?" icon to the right of the
73 // title text
74 font.setBold(true);
75 painter->setFont(font);
76 if (! index.data(StatusEventItem::HelpUrlRole).isNull()) {
77 // Draw the little "?" icon in the corner of the list item and
78 // account for it when eliding the title
79 title = fm.elidedText(title,
80 Qt::ElideRight,
81 textRect.width() - _helpIcon.width() - 24);
82
83 x = textRect.topRight().x() - _helpIcon.width() - 8;
84 y = textRect.y() + 8;
85 painter->drawPixmap(x, y, _helpIcon);
86 } else {
87 title = fm.elidedText(title, Qt::ElideRight, textRect.width() - 16);
88 }
89 painter->drawText(textRect.x(),
90 textRect.y() + 8,
91 textRect.width(),
92 fm.lineSpacing(),
93 Qt::AlignVCenter | Qt::AlignLeft, title);
94
95 // Draw the rest of the event text, up to a maximum of 2 lines for
96 // unselected items or 5 lines for selected items. Any extra text will
97 // be elided.
98 font.setBold(false);
99 painter->setFont(font);
100 if (option.state & QStyle::State_Selected)
101 text = layoutText(text, font, textRect.width(), 6).join("\n");
102 else
103 text = layoutText(text, font, textRect.width(), 3).join("\n");
104
105 x = textRect.x();
106 y = textRect.y() + 8 + fm.leading() + fm.lineSpacing();
107 painter->drawText(x, y,
108 textRect.width(),
109 textRect.height() - (y - textRect.y()),
110 Qt::AlignTop | Qt::AlignLeft, text);
111
112 painter->restore();
113}
114
115QSize
116StatusEventItemDelegate::sizeHint(const QStyleOptionViewItem &option,
117 const QModelIndex &index) const
118{
119 int iconHeight, iconWidth;
120 int textWidth, textHeight;
121 QFontMetrics fontMetrics = option.fontMetrics;
122
123 QPixmap icon = index.data(StatusEventItem::IconRole).value<QPixmap>();
124 QString text = index.data(StatusEventItem::DescriptionRole).toString();
125 QTime tstamp = index.data(StatusEventItem::TimestampRole).toTime();
126
127 iconHeight = icon.height() + fontMetrics.lineSpacing() + 16;
128 iconWidth = qMax(fontMetrics.width(tstamp.toString()), icon.width()) + 16;
129 textWidth = option.rect.width() - iconWidth;
130
131 if (option.state & QStyle::State_Selected)
132 layoutText(text, option.font, textWidth, 6, &textHeight);
133 else
134 layoutText(text, option.font, textWidth, 3, &textHeight);
135 textHeight += 8 + fontMetrics.leading() + fontMetrics.lineSpacing();
136
137 return QSize(option.rect.width(), qMax(iconHeight, textHeight));
138}
139
140QStringList
142 const QFont &font,
143 int maxLineWidth,
144 int maxLines,
145 int *textHeight)
146{
147 QTextLayout textLayout(text, font);
148 QFontMetrics fontMetrics(font);
149 QStringList lines;
150 qreal height = 0.0;
151
152 textLayout.beginLayout();
153 while (lines.size() < maxLines) {
154 QTextLine line = textLayout.createLine();
155 if (! line.isValid())
156 break;
157 if (maxLines <= 0 || lines.size() < maxLines-1) {
158 // Wrap the current line at or below the maximum line width
159 line.setLineWidth(maxLineWidth);
160 lines.append(text.mid(line.textStart(), line.textLength()));
161 } else {
162 // Set the line width beyond the max line width, and then elide it
163 // so the user has a visible indication that the full message is
164 // longer than what is visible.
165 line.setLineWidth(2 * maxLineWidth);
166 lines.append(fontMetrics.elidedText(text.mid(line.textStart()),
167 Qt::ElideRight,
168 maxLineWidth));
169 }
170 height += fontMetrics.leading() + line.height();
171 }
172 textLayout.endLayout();
173
174 if (textHeight)
175 *textHeight = qRound(height);
176
177 return lines;
178}
179
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
static QStringList layoutText(const QString &text, const QFont &fontMetrics, int maxLineWidth, int maxLines=-1, int *textHeight=0)
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
StatusEventItemDelegate(QObject *parent=0)