• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Plasma

delegate.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright 2007 Robert Knight <robertknight@gmail.com>
00003     Copyright 2007 Kevin Ottens <ervin@kde.org>
00004     Copyright 2008 Marco Martin <notmart@gmail.com>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 // Own
00023 #include "delegate.h"
00024 
00025 #include <cmath>
00026 #include <math.h>
00027 
00028 // Qt
00029 #include <QApplication>
00030 #include <QFontMetrics>
00031 #include <QIcon>
00032 #include <QModelIndex>
00033 #include <QPainter>
00034 #include <QStyleOptionViewItem>
00035 
00036 // KDE
00037 #include <kcolorutils.h>
00038 #include <kdebug.h>
00039 #include <kglobal.h>
00040 #include <kglobalsettings.h>
00041 #include <kcolorscheme.h>
00042 
00043 // plasma
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     //if title=subtitle subtitle won't be displayed
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>();// true;
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     // draw icon
00259     QIcon decorationIcon = index.data(Qt::DecorationRole).value<QIcon>();
00260 
00261     if (index.data(d->roles[ColumnTypeRole]).toInt() == SecondaryActionColumn) {
00262         if (hover) {
00263             // Only draw on hover
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         // as default always draw as main column
00270         decorationIcon.paint(painter, decorationRect, option.decorationAlignment);
00271     }
00272 
00273     painter->save();
00274 
00275     // draw title
00276     painter->setFont(titleFont);
00277     painter->drawText(titleRect, Qt::AlignLeft|Qt::AlignVCenter, titleText);
00278 
00279     if (hover || !uniqueTitle) {
00280         // draw sub-title, BUT only if:
00281         //   * it isn't a unique title, this allows two items to have the same title and be
00282         //          disambiguated by their subtitle
00283         //   * we are directed by the model that this item should never be treated as unique
00284         //          e.g. the documents list in the recently used tab
00285         //   * the mouse is hovered over the item, causing the additional information to be
00286         //          displayed
00287         //
00288         // the rational for this is that subtitle text should in most cases not be
00289         // required to understand the item itself and that showing all the subtexts in a
00290         // listing makes the information density very high, impacting both the speed at
00291         // which one can scan the list visually and the aesthetic qualities of the listing.
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             // draw it on the right side
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         // use a slightly translucent version of the palette's highlight color
00352         // for the background
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             //clip right (or left for rtl languages) to make the connection with the next column
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             //reverse the gradient
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         //last column, clip left (right for rtl)
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         //column < columns-1; clip both ways
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 //    kDebug() << "size hint is" << size << (metrics.height() + subMetrics.ascent());
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 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal