00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "delegate.h"
00024
00025 #include <cmath>
00026 #include <math.h>
00027
00028
00029 #include <QApplication>
00030 #include <QFontMetrics>
00031 #include <QIcon>
00032 #include <QModelIndex>
00033 #include <QPainter>
00034 #include <QStyleOptionViewItem>
00035
00036
00037 #include <KColorUtils>
00038 #include <KDebug>
00039 #include <KGlobal>
00040 #include <KGlobalSettings>
00041 #include <KColorScheme>
00042
00043
00044 #include <plasma/paintutils.h>
00045
00046 namespace Plasma
00047 {
00048
00049 class DelegatePrivate
00050 {
00051 public:
00052 DelegatePrivate() { }
00053
00054 ~DelegatePrivate() { }
00055
00056 QFont fontForSubTitle(const QFont& titleFont) const;
00057 QRect titleRect(const QStyleOptionViewItem& option, const QModelIndex& index) const;
00058 QRect subTitleRect(const QStyleOptionViewItem& option, const QModelIndex& index) const;
00059
00060 QMap<int, int> roles;
00061
00062 static const int ICON_TEXT_MARGIN = 10;
00063 static const int TEXT_RIGHT_MARGIN = 5;
00064 static const int ACTION_ICON_SIZE = 22;
00065
00066 static const int ITEM_LEFT_MARGIN = 5;
00067 static const int ITEM_RIGHT_MARGIN = 5;
00068 static const int ITEM_TOP_MARGIN = 5;
00069 static const int ITEM_BOTTOM_MARGIN = 5;
00070 };
00071
00072
00073 QFont DelegatePrivate::fontForSubTitle(const QFont& titleFont) const
00074 {
00075 QFont subTitleFont = titleFont;
00076 subTitleFont.setPointSize(qMax(subTitleFont.pointSize() - 2,
00077 KGlobalSettings::smallestReadableFont().pointSize()));
00078 return subTitleFont;
00079 }
00080
00081 QRect DelegatePrivate::titleRect(const QStyleOptionViewItem& option, const QModelIndex& index) const
00082 {
00083 QFont font(option.font);
00084 font.setBold(true);
00085 QFontMetrics fm(font);
00086
00087 Qt::Alignment textAlignment = option.decorationAlignment & Qt::AlignRight ? Qt::AlignRight : Qt::AlignLeft;
00088
00089 QRect emptyRect;
00090 if (option.direction == Qt::LeftToRight) {
00091 emptyRect = option.rect.adjusted(option.decorationSize.width()+ICON_TEXT_MARGIN+ITEM_LEFT_MARGIN, ITEM_TOP_MARGIN, -ITEM_RIGHT_MARGIN, -ITEM_BOTTOM_MARGIN);
00092 } else {
00093 emptyRect = option.rect.adjusted(ITEM_LEFT_MARGIN, ITEM_TOP_MARGIN, -ITEM_RIGHT_MARGIN-option.decorationSize.width()-ICON_TEXT_MARGIN, -ITEM_BOTTOM_MARGIN);
00094 }
00095
00096 if (emptyRect.width() < 0) {
00097 emptyRect.setWidth(0);
00098 return emptyRect;
00099 }
00100
00101 QRect textRect = QStyle::alignedRect(option.direction,
00102 textAlignment,
00103 fm.boundingRect(index.data(Qt::DisplayRole).toString()).size(),
00104 emptyRect);
00105
00106 textRect.setWidth(textRect.width() + TEXT_RIGHT_MARGIN);
00107 textRect.setHeight(emptyRect.height()/2);
00108 return textRect;
00109 }
00110
00111 QRect DelegatePrivate::subTitleRect(const QStyleOptionViewItem& option, const QModelIndex& index) const
00112 {
00113 QString subTitle = index.data(roles[Delegate::SubTitleRole]).toString();
00114
00115 QFontMetrics fm(fontForSubTitle(option.font));
00116
00117 QRect textRect = titleRect(option, index);
00118 int right = textRect.right();
00119
00120
00121 if (subTitle != index.data(Qt::DisplayRole).toString()) {
00122 textRect.setWidth(fm.width(" " + subTitle) + TEXT_RIGHT_MARGIN);
00123 } else {
00124 textRect.setWidth(0);
00125 }
00126 textRect.translate(0, textRect.height());
00127
00128 if (option.direction == Qt::RightToLeft) {
00129 textRect.moveRight(right);
00130 }
00131
00132 return textRect;
00133 }
00134
00135 Delegate::Delegate(QObject *parent)
00136 : QAbstractItemDelegate(parent),
00137 d(new DelegatePrivate)
00138 {
00139 }
00140
00141 Delegate::~Delegate()
00142 {
00143 delete d;
00144 }
00145
00146 void Delegate::setRoleMapping(SpecificRoles role, int actual)
00147 {
00148 d->roles[role] = actual;
00149 }
00150
00151 int Delegate::roleMapping(SpecificRoles role) const
00152 {
00153 return d->roles[role];
00154 }
00155
00156 QRect Delegate::rectAfterTitle(const QStyleOptionViewItem& option, const QModelIndex& index) const
00157 {
00158 QRect textRect = d->titleRect(option, index);
00159
00160 QRect emptyRect(0, textRect.top(), option.rect.width() - textRect.width() - DelegatePrivate::ITEM_LEFT_MARGIN - DelegatePrivate::ITEM_RIGHT_MARGIN - option.decorationSize.width() - DelegatePrivate::ICON_TEXT_MARGIN, textRect.height());
00161
00162 if (option.direction == Qt::LeftToRight) {
00163 emptyRect.moveLeft(textRect.right());
00164 } else {
00165 emptyRect.moveRight(textRect.left());
00166 }
00167
00168 if (emptyRect.width() < 0) {
00169 emptyRect.setWidth(0);
00170 }
00171
00172 return emptyRect;
00173 }
00174
00175 QRect Delegate::rectAfterSubTitle(const QStyleOptionViewItem& option, const QModelIndex& index) const
00176 {
00177 QRect textRect = d->subTitleRect(option, index);
00178
00179 QRect emptyRect(0, textRect.top(), option.rect.width() - textRect.width() - DelegatePrivate::ITEM_LEFT_MARGIN - DelegatePrivate::ITEM_RIGHT_MARGIN - option.decorationSize.width() - DelegatePrivate::ICON_TEXT_MARGIN, textRect.height());
00180
00181 if (option.direction == Qt::LeftToRight) {
00182 emptyRect.moveLeft(textRect.right());
00183 } else {
00184 emptyRect.moveRight(textRect.left());
00185 }
00186
00187 if (emptyRect.width() < 0) {
00188 emptyRect.setWidth(0);
00189 }
00190
00191 return emptyRect;
00192 }
00193
00194 QRect Delegate::emptyRect(const QStyleOptionViewItem& option, const QModelIndex& index) const
00195 {
00196 QRect afterTitleRect = rectAfterTitle(option, index);
00197 QRect afterSubTitleRect = rectAfterSubTitle(option, index);
00198
00199 afterTitleRect.setHeight(afterTitleRect.height()*2);
00200 afterSubTitleRect.setTop(afterTitleRect.top());
00201
00202 return afterTitleRect.intersected(afterSubTitleRect);
00203 }
00204
00205
00206 void Delegate::paint(QPainter *painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
00207 {
00208 const bool hover = option.state & (QStyle::State_MouseOver | QStyle::State_Selected);
00209
00210 QRect contentRect = option.rect;
00211 contentRect.setBottom(contentRect.bottom() - 1);
00212
00213 QRect decorationRect = QStyle::alignedRect(option.direction,
00214 option.decorationPosition == QStyleOptionViewItem::Left ?
00215 Qt::AlignLeft : Qt::AlignRight,
00216 option.decorationSize,
00217 contentRect.adjusted(DelegatePrivate::ITEM_LEFT_MARGIN, DelegatePrivate::ITEM_TOP_MARGIN,-DelegatePrivate::ITEM_RIGHT_MARGIN,-DelegatePrivate::ITEM_BOTTOM_MARGIN));
00218 decorationRect.moveTop(contentRect.top() + qMax(0, (contentRect.height() - decorationRect.height())) / 2);
00219
00220 QString titleText = index.data(Qt::DisplayRole).value<QString>();
00221 QString subTitleText = index.data(d->roles[SubTitleRole]).value<QString>();
00222
00223 QRect titleRect = d->titleRect(option, index);
00224 QRect subTitleRect = d->subTitleRect(option, index);
00225
00226
00227 bool uniqueTitle = !index.data(d->roles[SubTitleMandatoryRole]).value<bool>();
00228 if (uniqueTitle) {
00229 QModelIndex sib = index.sibling(index.row() + 1, index.column());
00230 if (sib.isValid()) {
00231 uniqueTitle = sib.data(Qt::DisplayRole).value<QString>() != titleText;
00232 }
00233
00234 if (uniqueTitle) {
00235 sib = index.sibling(index.row() + -1, index.column());
00236 if (sib.isValid()) {
00237 uniqueTitle = sib.data(Qt::DisplayRole).value<QString>() != titleText;
00238 }
00239 }
00240 }
00241
00242 if (subTitleText == titleText) {
00243 subTitleText = QString();
00244 }
00245
00246 QFont subTitleFont = d->fontForSubTitle(option.font);
00247
00248 QFont titleFont(option.font);
00249
00250 if (hover) {
00251 painter->save();
00252 painter->setRenderHint(QPainter::Antialiasing);
00253
00254 const int column = index.column();
00255 const int columns = index.model()->columnCount();
00256 const int roundedRadius = 5;
00257
00258
00259
00260 QColor backgroundColor = option.palette.color(QPalette::Highlight);
00261 backgroundColor.setAlphaF(0.2);
00262
00263 QColor backgroundColor2 = option.palette.color(QPalette::Highlight);
00264 backgroundColor.setAlphaF(0.5);
00265
00266 QRect highlightRect = option.rect.adjusted(2, 2, -2, -2);
00267
00268 QPen outlinePen(backgroundColor, 2);
00269
00270 if (column == 0) {
00271
00272 if (columns > 1) {
00273 if (option.direction == Qt::LeftToRight) {
00274 painter->setClipRect(option.rect);
00275 highlightRect.adjust(0, 0, roundedRadius, 0);
00276 } else {
00277 painter->setClipRect(option.rect);
00278 highlightRect.adjust(-roundedRadius, 0, 0, 0);
00279 }
00280 }
00281
00282 QLinearGradient gradient(highlightRect.topLeft(), highlightRect.topRight());
00283
00284
00285 if (option.direction == Qt::RightToLeft) {
00286 gradient.setStart(highlightRect.topRight());
00287 gradient.setFinalStop(highlightRect.topLeft());
00288 }
00289
00290 gradient.setColorAt(0, backgroundColor);
00291
00292 gradient.setColorAt(((qreal)titleRect.width()/3.0) / (qreal)highlightRect.width(), backgroundColor2);
00293
00294 gradient.setColorAt(0.7, backgroundColor);
00295
00296 outlinePen.setBrush(gradient);
00297
00298
00299 } else if (column == columns-1) {
00300 if (option.direction == Qt::LeftToRight) {
00301 painter->setClipRect(option.rect);
00302 highlightRect.adjust(-roundedRadius, 0, 0, 0);
00303 } else {
00304 painter->setClipRect(option.rect);
00305 highlightRect.adjust(0, 0, +roundedRadius, 0);
00306 }
00307
00308
00309 } else {
00310 painter->setClipRect(option.rect);
00311 highlightRect.adjust(-roundedRadius, 0, +roundedRadius, 0);
00312 }
00313
00314 painter->setPen(outlinePen);
00315 painter->drawPath(PaintUtils::roundedRectangle(highlightRect, roundedRadius));
00316
00317 painter->restore();
00318 }
00319
00320
00321 QIcon decorationIcon = index.data(Qt::DecorationRole).value<QIcon>();
00322
00323 if (index.data(d->roles[ColumnTypeRole]).toInt() == SecondaryActionColumn) {
00324 if (hover) {
00325
00326 const int delta = floor((qreal)(option.decorationSize.width() - DelegatePrivate::ACTION_ICON_SIZE)/2.0);
00327 decorationRect.adjust(delta, delta-1, -delta-1, -delta);
00328 decorationIcon.paint(painter, decorationRect, option.decorationAlignment);
00329 }
00330 } else {
00331
00332 decorationIcon.paint(painter, decorationRect, option.decorationAlignment);
00333 }
00334
00335 painter->save();
00336
00337
00338 painter->setFont(titleFont);
00339 painter->drawText(titleRect, Qt::AlignLeft|Qt::AlignVCenter, titleText);
00340
00341 if (hover || !uniqueTitle) {
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 painter->setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText), 1));
00355 painter->setFont(subTitleFont);
00356 painter->drawText(subTitleRect, Qt::AlignLeft|Qt::AlignVCenter, " " + subTitleText);
00357 }
00358
00359 painter->restore();
00360
00361 }
00362
00363 QSize Delegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
00364 {
00365 Q_UNUSED(index)
00366 QSize size = option.rect.size();
00367
00368 QFontMetrics metrics(option.font);
00369
00370 QFontMetrics subMetrics(d->fontForSubTitle(option.font));
00371 size.setHeight(qMax(option.decorationSize.height(), qMax(size.height(), metrics.height() + subMetrics.ascent()) + 3) + 4);
00372
00373
00374 size*=1.1;
00375
00376 return size;
00377 }
00378
00379 }
00380
00381