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