Vidalia 0.2.10
|
00001 /* 00002 ** This file is part of Vidalia, and is subject to the license terms in the 00003 ** LICENSE file, found in the top level directory of this distribution. If you 00004 ** did not receive the LICENSE file with this file, you may obtain it from the 00005 ** Vidalia source package distributed by the Vidalia Project at 00006 ** http://www.vidalia-project.net/. No part of Vidalia, including this file, 00007 ** may be copied, modified, propagated, or distributed except according to the 00008 ** terms described in the LICENSE file. 00009 */ 00010 00011 /* 00012 ** \file StatusEventItemDelegate.cpp 00013 ** \version $Id: StatusEventItemDelegate.cpp 4080 2009-08-28 18:14:48Z edmanm $ 00014 ** \brief Handles custom painting of items in a StatusEventWidget 00015 */ 00016 00017 #include "StatusEventItemDelegate.h" 00018 #include "StatusEventItem.h" 00019 00020 #include "Vidalia.h" 00021 00022 #include <QPainter> 00023 #include <QTextLine> 00024 #include <QTextLayout> 00025 00026 StatusEventItemDelegate::StatusEventItemDelegate(QObject *parent) 00027 : QItemDelegate(parent) 00028 { 00029 _helpIcon = QPixmap(":/images/16x16/system-help.png"); 00030 } 00031 00032 void 00033 StatusEventItemDelegate::paint(QPainter *painter, 00034 const QStyleOptionViewItem &option, 00035 const QModelIndex &index) const 00036 { 00037 QItemDelegate::paint(painter, option, index); 00038 00039 painter->save(); 00040 if (option.state & QStyle::State_Selected) 00041 painter->setPen(option.palette.highlightedText().color()); 00042 00043 QPixmap icon = index.data(StatusEventItem::IconRole).value<QPixmap>(); 00044 QTime tstamp = index.data(StatusEventItem::TimestampRole).toTime(); 00045 QString title = index.data(StatusEventItem::TitleRole).toString(); 00046 QString text = index.data(StatusEventItem::DescriptionRole).toString(); 00047 QFont font = option.font; 00048 QFontMetrics fm = option.fontMetrics; 00049 00050 /* XXX: Handle right-to-left layouts here. */ 00051 QRect iconRect(option.rect.x(), 00052 option.rect.y(), 00053 qMax(fm.width(tstamp.toString()), icon.width()) + 16, 00054 option.rect.height()); 00055 QRect textRect(iconRect.topRight(), option.rect.bottomRight()); 00056 00057 // Draw the status icon 00058 QPoint center = iconRect.center(); 00059 int x = center.x() - qRound(icon.width() / 2.0); 00060 int y = center.y() - qRound((icon.height() + fm.lineSpacing()) / 2.0); 00061 painter->drawPixmap(x, y, icon); 00062 00063 // Draw the timestamp text underneath the status icon 00064 x = iconRect.x(); 00065 y = y + icon.height(); 00066 painter->drawText(x, y, 00067 iconRect.width(), 00068 fm.lineSpacing(), 00069 Qt::AlignCenter, 00070 tstamp.toString()); 00071 00072 // Draw the event's title in a bold font. If the current item has an 00073 // associated help URL, draw the little "?" icon to the right of the 00074 // title text 00075 font.setBold(true); 00076 painter->setFont(font); 00077 if (! index.data(StatusEventItem::HelpUrlRole).isNull()) { 00078 // Draw the little "?" icon in the corner of the list item and 00079 // account for it when eliding the title 00080 title = fm.elidedText(title, 00081 Qt::ElideRight, 00082 textRect.width() - _helpIcon.width() - 24); 00083 00084 x = textRect.topRight().x() - _helpIcon.width() - 8; 00085 y = textRect.y() + 8; 00086 painter->drawPixmap(x, y, _helpIcon); 00087 } else { 00088 title = fm.elidedText(title, Qt::ElideRight, textRect.width() - 16); 00089 } 00090 painter->drawText(textRect.x(), 00091 textRect.y() + 8, 00092 textRect.width(), 00093 fm.lineSpacing(), 00094 Qt::AlignVCenter | Qt::AlignLeft, title); 00095 00096 // Draw the rest of the event text, up to a maximum of 2 lines for 00097 // unselected items or 5 lines for selected items. Any extra text will 00098 // be elided. 00099 font.setBold(false); 00100 painter->setFont(font); 00101 if (option.state & QStyle::State_Selected) 00102 text = layoutText(text, font, textRect.width(), 6).join("\n"); 00103 else 00104 text = layoutText(text, font, textRect.width(), 3).join("\n"); 00105 00106 x = textRect.x(); 00107 y = textRect.y() + 8 + fm.leading() + fm.lineSpacing(); 00108 painter->drawText(x, y, 00109 textRect.width(), 00110 textRect.height() - (y - textRect.y()), 00111 Qt::AlignTop | Qt::AlignLeft, text); 00112 00113 painter->restore(); 00114 } 00115 00116 QSize 00117 StatusEventItemDelegate::sizeHint(const QStyleOptionViewItem &option, 00118 const QModelIndex &index) const 00119 { 00120 int iconHeight, iconWidth; 00121 int textWidth, textHeight; 00122 QFontMetrics fontMetrics = option.fontMetrics; 00123 00124 QPixmap icon = index.data(StatusEventItem::IconRole).value<QPixmap>(); 00125 QString text = index.data(StatusEventItem::DescriptionRole).toString(); 00126 QTime tstamp = index.data(StatusEventItem::TimestampRole).toTime(); 00127 00128 iconHeight = icon.height() + fontMetrics.lineSpacing() + 16; 00129 iconWidth = qMax(fontMetrics.width(tstamp.toString()), icon.width()) + 16; 00130 textWidth = option.rect.width() - iconWidth; 00131 00132 if (option.state & QStyle::State_Selected) 00133 layoutText(text, option.font, textWidth, 6, &textHeight); 00134 else 00135 layoutText(text, option.font, textWidth, 3, &textHeight); 00136 textHeight += 8 + fontMetrics.leading() + fontMetrics.lineSpacing(); 00137 00138 return QSize(option.rect.width(), qMax(iconHeight, textHeight)); 00139 } 00140 00141 QStringList 00142 StatusEventItemDelegate::layoutText(const QString &text, 00143 const QFont &font, 00144 int maxLineWidth, 00145 int maxLines, 00146 int *textHeight) 00147 { 00148 QTextLayout textLayout(text, font); 00149 QFontMetrics fontMetrics(font); 00150 QStringList lines; 00151 qreal height = 0.0; 00152 00153 textLayout.beginLayout(); 00154 while (lines.size() < maxLines) { 00155 QTextLine line = textLayout.createLine(); 00156 if (! line.isValid()) 00157 break; 00158 if (maxLines <= 0 || lines.size() < maxLines-1) { 00159 // Wrap the current line at or below the maximum line width 00160 line.setLineWidth(maxLineWidth); 00161 lines.append(text.mid(line.textStart(), line.textLength())); 00162 } else { 00163 // Set the line width beyond the max line width, and then elide it 00164 // so the user has a visible indication that the full message is 00165 // longer than what is visible. 00166 line.setLineWidth(2 * maxLineWidth); 00167 lines.append(fontMetrics.elidedText(text.mid(line.textStart()), 00168 Qt::ElideRight, 00169 maxLineWidth)); 00170 } 00171 height += fontMetrics.leading() + line.height(); 00172 } 00173 textLayout.endLayout(); 00174 00175 if (textHeight) 00176 *textHeight = qRound(height); 00177 00178 return lines; 00179 } 00180