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.h>
00038 #include <kdebug.h>
00039 #include <kglobal.h>
00040 #include <kglobalsettings.h>
00041 #include <kcolorscheme.h>
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 bool m_showToolTip;
00072 };
00073
00074 QFont DelegatePrivate::fontForSubTitle(const QFont &titleFont) const
00075 {
00076 QFont subTitleFont = titleFont;
00077 subTitleFont.setPointSize(qMax(subTitleFont.pointSize() - 2,
00078 KGlobalSettings::smallestReadableFont().pointSize()));
00079 return subTitleFont;
00080 }
00081
00082 QRect DelegatePrivate::titleRect(const QStyleOptionViewItem &option, const QModelIndex &index) const
00083 {
00084 QFont font(option.font);
00085 font.setBold(true);
00086 QFontMetrics fm(font);
00087
00088 Qt::Alignment textAlignment =
00089 option.decorationAlignment & Qt::AlignRight ? Qt::AlignRight : Qt::AlignLeft;
00090
00091 QRect emptyRect;
00092 if (option.direction == Qt::LeftToRight) {
00093 emptyRect = option.rect.adjusted(
00094 option.decorationSize.width() + ICON_TEXT_MARGIN + ITEM_LEFT_MARGIN,
00095 ITEM_TOP_MARGIN, -ITEM_RIGHT_MARGIN, -ITEM_BOTTOM_MARGIN);
00096 } else {
00097 emptyRect = option.rect.adjusted(
00098 ITEM_LEFT_MARGIN, ITEM_TOP_MARGIN,
00099 -ITEM_RIGHT_MARGIN - option.decorationSize.width() - ICON_TEXT_MARGIN, -ITEM_BOTTOM_MARGIN);
00100 }
00101
00102 if (emptyRect.width() < 0) {
00103 emptyRect.setWidth(0);
00104 return emptyRect;
00105 }
00106
00107 QRect textRect = QStyle::alignedRect(
00108 option.direction,
00109 textAlignment,
00110 fm.boundingRect(index.data(Qt::DisplayRole).toString()).size(),
00111 emptyRect);
00112
00113 textRect.setWidth(textRect.width() + TEXT_RIGHT_MARGIN);
00114 textRect.setHeight(emptyRect.height() / 2);
00115 return textRect;
00116 }
00117
00118 QRect DelegatePrivate::subTitleRect(const QStyleOptionViewItem &option,
00119 const QModelIndex &index) const
00120 {
00121 QString subTitle = index.data(roles[Delegate::SubTitleRole]).toString();
00122
00123 QFontMetrics fm(fontForSubTitle(option.font));
00124
00125 QRect textRect = titleRect(option, index);
00126 int right = textRect.right();
00127
00128
00129 if (subTitle != index.data(Qt::DisplayRole).toString()) {
00130 textRect.setWidth(fm.width(" " + subTitle) + TEXT_RIGHT_MARGIN);
00131 } else {
00132 textRect.setWidth(0);
00133 }
00134 textRect.translate(0, textRect.height());
00135
00136 if (option.direction == Qt::RightToLeft) {
00137 textRect.moveRight(right);
00138 }
00139
00140 return textRect;
00141 }
00142
00143 Delegate::Delegate(QObject *parent)
00144 : QAbstractItemDelegate(parent),
00145 d(new DelegatePrivate)
00146 {
00147 }
00148
00149 Delegate::~Delegate()
00150 {
00151 delete d;
00152 }
00153
00154 void Delegate::setRoleMapping(SpecificRoles role, int actual)
00155 {
00156 d->roles[role] = actual;
00157 }
00158
00159 int Delegate::roleMapping(SpecificRoles role) const
00160 {
00161 return d->roles[role];
00162 }
00163
00164 QRect Delegate::rectAfterTitle(const QStyleOptionViewItem &option, const QModelIndex &index) const
00165 {
00166 QRect textRect = d->titleRect(option, index);
00167
00168 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());
00169
00170 if (option.direction == Qt::LeftToRight) {
00171 emptyRect.moveLeft(textRect.right());
00172 } else {
00173 emptyRect.moveRight(textRect.left());
00174 }
00175
00176 if (emptyRect.width() < 0) {
00177 emptyRect.setWidth(0);
00178 }
00179
00180 return emptyRect;
00181 }
00182
00183 QRect Delegate::rectAfterSubTitle(const QStyleOptionViewItem &option, const QModelIndex &index) const
00184 {
00185 QRect textRect = d->subTitleRect(option, index);
00186
00187 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());
00188
00189 if (option.direction == Qt::LeftToRight) {
00190 emptyRect.moveLeft(textRect.right());
00191 } else {
00192 emptyRect.moveRight(textRect.left());
00193 }
00194
00195 if (emptyRect.width() < 0) {
00196 emptyRect.setWidth(0);
00197 }
00198
00199 return emptyRect;
00200 }
00201
00202 QRect Delegate::emptyRect(const QStyleOptionViewItem &option, const QModelIndex &index) const
00203 {
00204 QRect afterTitleRect = rectAfterTitle(option, index);
00205 QRect afterSubTitleRect = rectAfterSubTitle(option, index);
00206
00207 afterTitleRect.setHeight(afterTitleRect.height() * 2);
00208 afterSubTitleRect.setTop(afterTitleRect.top());
00209
00210 return afterTitleRect.intersected(afterSubTitleRect);
00211 }
00212
00213 void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
00214 const QModelIndex &index) const
00215 {
00216 const bool hover = option.state & (QStyle::State_MouseOver | QStyle::State_Selected);
00217
00218 QRect contentRect = option.rect;
00219 contentRect.setBottom(contentRect.bottom() - 1);
00220
00221 QRect decorationRect =
00222 QStyle::alignedRect(option.direction,
00223 option.decorationPosition == QStyleOptionViewItem::Left ?
00224 Qt::AlignLeft : Qt::AlignRight,
00225 option.decorationSize,
00226 contentRect.adjusted(DelegatePrivate::ITEM_LEFT_MARGIN, DelegatePrivate::ITEM_TOP_MARGIN, -DelegatePrivate::ITEM_RIGHT_MARGIN, -DelegatePrivate::ITEM_BOTTOM_MARGIN));
00227 decorationRect.moveTop(contentRect.top() + qMax(0, (contentRect.height() - decorationRect.height())) / 2);
00228
00229 QString titleText = index.data(Qt::DisplayRole).value<QString>();
00230 QString subTitleText = index.data(d->roles[SubTitleRole]).value<QString>();
00231
00232 QRect titleRect = d->titleRect(option, index);
00233 QRect subTitleRect = d->subTitleRect(option, index);
00234
00235 bool uniqueTitle = !index.data(d->roles[SubTitleMandatoryRole]).value<bool>();
00236 if (uniqueTitle) {
00237 QModelIndex sib = index.sibling(index.row() + 1, index.column());
00238 if (sib.isValid()) {
00239 uniqueTitle = sib.data(Qt::DisplayRole).value<QString>() != titleText;
00240 }
00241
00242 if (uniqueTitle) {
00243 sib = index.sibling(index.row() + -1, index.column());
00244 if (sib.isValid()) {
00245 uniqueTitle = sib.data(Qt::DisplayRole).value<QString>() != titleText;
00246 }
00247 }
00248 }
00249
00250 if (subTitleText == titleText) {
00251 subTitleText.clear();
00252 }
00253
00254 QFont subTitleFont = d->fontForSubTitle(option.font);
00255
00256 QFont titleFont(option.font);
00257
00258
00259 QIcon decorationIcon = index.data(Qt::DecorationRole).value<QIcon>();
00260
00261 if (index.data(d->roles[ColumnTypeRole]).toInt() == SecondaryActionColumn) {
00262 if (hover) {
00263
00264 const int delta = floor((qreal)(option.decorationSize.width() - DelegatePrivate::ACTION_ICON_SIZE) / 2.0);
00265 decorationRect.adjust(delta, delta-1, -delta-1, -delta);
00266 decorationIcon.paint(painter, decorationRect, option.decorationAlignment);
00267 }
00268 } else {
00269
00270 decorationIcon.paint(painter, decorationRect, option.decorationAlignment);
00271 }
00272
00273 painter->save();
00274
00275
00276 painter->setFont(titleFont);
00277 painter->drawText(titleRect, Qt::AlignLeft|Qt::AlignVCenter, titleText);
00278
00279 if (hover || !uniqueTitle) {
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 painter->setPen(QPen(KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText), 1));
00293 painter->setFont(subTitleFont);
00294 painter->drawText(subTitleRect, Qt::AlignLeft|Qt::AlignVCenter, " " + subTitleText);
00295 }
00296
00297 painter->restore();
00298
00299
00300 d->m_showToolTip = false;
00301
00302 painter->save();
00303 painter->setPen(Qt::NoPen);
00304 const QColor gradientColor =
00305 KColorScheme(QPalette::Active).background(KColorScheme::NormalBackground).color();
00306 if (option.direction == Qt::LeftToRight) {
00307 if (((titleRect.width() + decorationRect.width() + 10) > option.rect.width() ||
00308 (subTitleRect.width() + decorationRect.width() + 15) > option.rect.width()) &&
00309 (titleRect.width() > 120 || subTitleRect.width() > 120)) {
00310 QLinearGradient gr;
00311 QRect gradientRect(option.rect.width() - 30, titleRect.y(),
00312 80, titleRect.height() + subTitleRect.height());
00313
00314 gr.setStart(gradientRect.topLeft());
00315 gr.setFinalStop(gradientRect.topRight());
00316 gr.setColorAt(0.0, Qt::transparent);
00317 gr.setColorAt(0.7, gradientColor);
00318 painter->setBrush(QBrush(gr));
00319 painter->drawRect(gradientRect);
00320 d->m_showToolTip = true;
00321 }
00322
00323 } else {
00324 if (((titleRect.width() + decorationRect.width() + 10) > option.rect.width() ||
00325 (subTitleRect.width() + decorationRect.width() + 15 )> option.rect.width()) &&
00326 (titleRect.width() > 120 || subTitleRect.width() > 120)) {
00327 QLinearGradient gr;
00328 QRect gradientRect(option.rect.x() - 25, titleRect.y(),
00329 60, titleRect.height() + subTitleRect.height());
00330 gr.setStart(gradientRect.topRight());
00331 gr.setFinalStop(gradientRect.topLeft());
00332 gr.setColorAt(0.0, Qt::transparent);
00333 gr.setColorAt(0.6, gradientColor);
00334 painter->setBrush(QBrush(gr));
00335 painter->drawRect(gradientRect);
00336
00337 d->m_showToolTip = true;
00338 }
00339 }
00340
00341 painter->restore();
00342
00343 if (hover) {
00344 painter->save();
00345 painter->setRenderHint(QPainter::Antialiasing);
00346
00347 const int column = index.column();
00348 const int columns = index.model()->columnCount();
00349 const int roundedRadius = 5;
00350
00351
00352
00353 QColor backgroundColor = option.palette.color(QPalette::Highlight);
00354 backgroundColor.setAlphaF(0.2);
00355
00356 QColor backgroundColor2 = option.palette.color(QPalette::Highlight);
00357 backgroundColor.setAlphaF(0.5);
00358
00359 QRect highlightRect = option.rect.adjusted(2, 2, -2, -2);
00360
00361 QPen outlinePen(backgroundColor, 2);
00362
00363 if (column == 0) {
00364
00365 if (columns > 1) {
00366 if (option.direction == Qt::LeftToRight) {
00367 painter->setClipRect(option.rect);
00368 highlightRect.adjust(0, 0, roundedRadius, 0);
00369 } else {
00370 painter->setClipRect(option.rect);
00371 highlightRect.adjust(-roundedRadius, 0, 0, 0);
00372 }
00373 }
00374
00375 QLinearGradient gradient(highlightRect.topLeft(), highlightRect.topRight());
00376
00377
00378 if (option.direction == Qt::RightToLeft) {
00379 gradient.setStart(highlightRect.topRight());
00380 gradient.setFinalStop(highlightRect.topLeft());
00381 }
00382
00383 gradient.setColorAt(0, backgroundColor);
00384
00385 gradient.setColorAt(((qreal)titleRect.width()/3.0) / (qreal)highlightRect.width(), backgroundColor2);
00386
00387 gradient.setColorAt(0.7, backgroundColor);
00388
00389 outlinePen.setBrush(gradient);
00390
00391
00392 } else if (column == columns-1) {
00393 if (option.direction == Qt::LeftToRight) {
00394 painter->setClipRect(option.rect);
00395 highlightRect.adjust(-roundedRadius, 0, 0, 0);
00396 } else {
00397 painter->setClipRect(option.rect);
00398 highlightRect.adjust(0, 0, +roundedRadius, 0);
00399 }
00400
00401
00402 } else {
00403 painter->setClipRect(option.rect);
00404 highlightRect.adjust(-roundedRadius, 0, +roundedRadius, 0);
00405 }
00406
00407 painter->setPen(outlinePen);
00408 painter->drawPath(PaintUtils::roundedRectangle(highlightRect, roundedRadius));
00409
00410 painter->restore();
00411 }
00412
00413
00414 }
00415
00416 QSize Delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
00417 {
00418 Q_UNUSED(index)
00419 QSize size = option.rect.size();
00420
00421 QFontMetrics metrics(option.font);
00422
00423 QFontMetrics subMetrics(d->fontForSubTitle(option.font));
00424 size.setHeight(qMax(option.decorationSize.height(), qMax(size.height(), metrics.height() + subMetrics.ascent()) + 3) + 4);
00425
00426
00427 size *= 1.1;
00428
00429 return size;
00430 }
00431
00432 bool Delegate::showToolTip() const
00433 {
00434 return d->m_showToolTip;
00435 }
00436
00437 }
00438
00439 #include "delegate.moc"
00440