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