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

Kate

expandingdelegate.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "expandingdelegate.h"
00020 
00021 #include <QtGui/QTextLine>
00022 #include <QtGui/QPainter>
00023 #include <QtGui/QBrush>
00024 #include <QKeyEvent>
00025 #include <QTreeView>
00026 #include <QApplication>
00027 
00028 #include <kdebug.h>
00029 
00030 #include "expandingwidgetmodel.h"
00031 
00032 ExpandingDelegate::ExpandingDelegate(ExpandingWidgetModel* model, QObject* parent)
00033   : QItemDelegate(parent)
00034   , m_model(model)
00035 {
00036 }
00037 
00038 //Gets the background-color in the way QItemDelegate does it
00039 static QColor getUsedBackgroundColor(const QStyleOptionViewItem & option, const QModelIndex& index) {
00040 if (option.showDecorationSelected && (option.state & QStyle::State_Selected)) {
00041         QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
00042                                   ? QPalette::Normal : QPalette::Disabled;
00043         if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
00044             cg = QPalette::Inactive;
00045 
00046         return option.palette.brush(cg, QPalette::Highlight).color();
00047     } else {
00048         QVariant value = index.data(Qt::BackgroundRole);
00049         if (qVariantCanConvert<QBrush>(value))
00050         return qvariant_cast<QBrush>(value).color();
00051     }
00052     
00053     return QColor();
00054 }
00055 
00056 static void dampColors(QColor& col) {
00057   //Reduce the colors that are less visible to the eye, because they are closer to black when it comes to contrast
00058   //The most significant color to the eye is green. Then comes red, and then blue, with blue _much_ less significant.
00059   
00060   col.setBlue(0);
00061   col.setRed(col.red() / 2);
00062 }
00063 
00064 //A hack to compute more eye-focused contrast values
00065 static double readabilityContrast(QColor foreground, QColor background) {
00066   dampColors(foreground);
00067   dampColors(background);
00068   return abs(foreground.green()-background.green()) + abs(foreground.red()-background.red()) + abs(foreground.blue() - background.blue());
00069 }
00070 
00071 void ExpandingDelegate::paint( QPainter * painter, const QStyleOptionViewItem & optionOld, const QModelIndex & index ) const
00072 {
00073   QStyleOptionViewItem option(optionOld);
00074 
00075   adjustStyle(index, option);
00076     
00077   if( index.column() == 0 )
00078     model()->placeExpandingWidget(index);
00079 
00080   //Make sure the decorations are painted at the top, because the center of expanded items will be filled with the embedded widget.
00081   if( model()->isPartiallyExpanded(index) == ExpandingWidgetModel::ExpandUpwards )
00082     m_cachedAlignment = Qt::AlignBottom;
00083   else
00084     m_cachedAlignment = Qt::AlignTop;
00085   
00086   option.decorationAlignment = m_cachedAlignment;
00087   option.displayAlignment = m_cachedAlignment;
00088   
00089   //kDebug( 13035 ) << "Painting row " << index.row() << ", column " << index.column() << ", internal " << index.internalPointer() << ", drawselected " << option.showDecorationSelected << ", selected " << (option.state & QStyle::State_Selected);
00090 
00091   m_cachedHighlights.clear();
00092   m_backgroundColor = getUsedBackgroundColor(option, index);
00093 
00094   if (!model()->indexIsItem(index) )
00095       return QItemDelegate::paint(painter, option, index);
00096 
00097   m_currentColumnStart = 0;
00098   m_cachedHighlights = createHighlighting(index, option);
00099 
00100   /*kDebug( 13035 ) << "Highlights for line:";
00101   foreach (const QTextLayout::FormatRange& fr, m_cachedHighlights)
00102     kDebug( 13035 ) << fr.start << " len " << fr.length << " format ";*/
00103 
00104   QItemDelegate::paint(painter, option, index);
00105 }
00106 
00107 QList<QTextLayout::FormatRange> ExpandingDelegate::createHighlighting(const QModelIndex& index, QStyleOptionViewItem& option) const {
00108   Q_UNUSED( index );
00109   Q_UNUSED( option );
00110   return QList<QTextLayout::FormatRange>();
00111 }
00112 
00113 QSize ExpandingDelegate::basicSizeHint( const QModelIndex& index ) const {
00114   return QItemDelegate::sizeHint( QStyleOptionViewItem(), index );
00115 }
00116 
00117 QSize ExpandingDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
00118 {
00119   QSize s = QItemDelegate::sizeHint( option, index );
00120   if( model()->isExpanded(index) && model()->expandingWidget( index ) )
00121   {
00122     QWidget* widget = model()->expandingWidget( index );
00123     QSize widgetSize = widget->size();
00124 
00125     s.setHeight( widgetSize.height() + s.height() + 10 ); //10 is the sum that must match exactly the offsets used in ExpandingWidgetModel::placeExpandingWidgets
00126   } else if( model()->isPartiallyExpanded( index ) ) {
00127     s.setHeight( s.height() + 30 + 10 );
00128   }
00129   return s;
00130 }
00131 
00132 void ExpandingDelegate::adjustStyle( const QModelIndex& index, QStyleOptionViewItem & option ) const
00133 {
00134 }
00135 
00136 void ExpandingDelegate::drawDisplay( QPainter * painter, const QStyleOptionViewItem & option, const QRect & rect, const QString & text ) const
00137 {
00138 /*  if (m_cachedRow == -1)
00139     return QItemDelegate::drawDisplay(painter, option, rect, text);
00140 */
00141   QTextLayout layout(text, option.font, painter->device());
00142 
00143   QRect textRect = rect.adjusted(1, 0, -1, 0); // remove width padding
00144 
00145   QList<QTextLayout::FormatRange> additionalFormats;
00146 
00147   int missingFormats = text.length();
00148   
00149   for (int i = 0; i < m_cachedHighlights.count(); ++i) {
00150     if (m_cachedHighlights[i].start + m_cachedHighlights[i].length <= m_currentColumnStart)
00151       continue;
00152 
00153     if (!additionalFormats.count())
00154       if (i != 0 && m_cachedHighlights[i - 1].start + m_cachedHighlights[i - 1].length > m_currentColumnStart) {
00155         QTextLayout::FormatRange before;
00156         before.start = 0;
00157         before.length = m_cachedHighlights[i - 1].start + m_cachedHighlights[i - 1].length - m_currentColumnStart;
00158         before.format = m_cachedHighlights[i - 1].format;
00159         additionalFormats.append(before);
00160       }
00161 
00162       
00163     QTextLayout::FormatRange format;
00164     format.start = m_cachedHighlights[i].start - m_currentColumnStart;
00165     format.length = m_cachedHighlights[i].length;
00166     format.format = m_cachedHighlights[i].format;
00167 
00168     additionalFormats.append(format);
00169   }
00170   if(!additionalFormats.isEmpty())
00171     missingFormats = text.length() - (additionalFormats.back().length + additionalFormats.back().start);
00172 
00173   if (missingFormats > 0) {
00174     QTextLayout::FormatRange format;
00175     format.start = text.length() - missingFormats;
00176     format.length = missingFormats;
00177     QTextCharFormat fm;
00178     fm.setForeground(option.palette.text());
00179     format.format = fm;
00180     additionalFormats.append(format);
00181   }
00182   
00183   if(m_backgroundColor.isValid()) {
00184     QColor background = m_backgroundColor;
00185 //     kDebug() << text << "background:" << background;
00186     //Now go through the formats, and make sure the contrast background/foreground is readable
00187     for(int a = 0; a < additionalFormats.size(); ++a) {
00188       QColor currentBackground = background;
00189       if(additionalFormats[a].format.hasProperty(QTextFormat::BackgroundBrush))
00190            currentBackground = additionalFormats[a].format.background().color();
00191       
00192       QColor currentColor = additionalFormats[a].format.foreground().color();
00193       
00194       double currentContrast = readabilityContrast(currentColor, currentBackground);
00195       QColor invertedColor(0xffffffff-additionalFormats[a].format.foreground().color().rgb());
00196       double invertedContrast = readabilityContrast(invertedColor, currentBackground);
00197       
00198 //       kDebug() << "values:" << invertedContrast << currentContrast << invertedColor << currentColor;
00199       
00200       if(invertedContrast > currentContrast) {
00201 //         kDebug() << text << additionalFormats[a].length << "switching from" << currentColor << "to" << invertedColor;
00202         QBrush b(additionalFormats[a].format.foreground());
00203         b.setColor(invertedColor);
00204         additionalFormats[a].format.setForeground(b);
00205       }
00206     }
00207   }
00208   
00209   for(int a = additionalFormats.size()-1; a >= 0; --a) {
00210       if(additionalFormats[a].length == 0){
00211           additionalFormats.removeAt(a);
00212       }else{
00215           QTextCharFormat fm;
00216           fm.setForeground(QBrush(additionalFormats[a].format.foreground().color()));
00217           fm.setBackground(additionalFormats[a].format.background());
00218       fm.setUnderlineStyle( additionalFormats[a].format.underlineStyle() );
00219       fm.setUnderlineColor( additionalFormats[a].format.underlineColor() );
00220       fm.setFontWeight( additionalFormats[a].format.fontWeight() );
00221           additionalFormats[a].format = fm;
00222       }
00223   }
00224 
00225 //   kDebug( 13035 ) << "Highlights for text [" << text << "] col start " << m_currentColumnStart << ":";
00226 //   foreach (const QTextLayout::FormatRange& fr, additionalFormats)
00227 //     kDebug( 13035 ) << fr.start << " len " << fr.length << "foreground" << fr.format.foreground() << "background" << fr.format.background();
00228 
00229   layout.setAdditionalFormats(additionalFormats);
00230 
00231   QTextOption to;
00232   
00233   to.setAlignment( m_cachedAlignment );
00234   
00235   to.setWrapMode(QTextOption::WrapAnywhere);
00236   layout.setTextOption(to);
00237 
00238   layout.beginLayout();
00239   QTextLine line = layout.createLine();
00240   line.setLineWidth(rect.width());
00241   layout.endLayout();
00242 
00243   //We need to do some hand layouting here
00244   if( to.alignment() & Qt::AlignBottom)
00245       layout.draw(painter, QPoint(rect.left(), rect.bottom() - (int)line.height()) );
00246   else
00247       layout.draw(painter, rect.topLeft() );
00248   
00249   return;
00250 
00251   //if (painter->fontMetrics().width(text) > textRect.width() && !text.contains(QLatin1Char('\n')))
00252       //str = elidedText(option.fontMetrics, textRect.width(), option.textElideMode, text);
00253   //qt_format_text(option.font, textRect, option.displayAlignment, str, 0, 0, 0, 0, painter);
00254 }
00255 
00256 void ExpandingDelegate::drawBackground ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
00257     QStyleOptionViewItemV4 opt = option;
00258     //initStyleOption(&opt, index);
00259     //Problem: This isn't called at all, because drawBrackground is not virtual :-/
00260     QStyle *style = model()->treeView()->style() ? model()->treeView()->style() : QApplication::style();
00261     style->drawControl(QStyle::CE_ItemViewItem, &opt, painter);
00262 }
00263 
00264 ExpandingWidgetModel* ExpandingDelegate::model() const {
00265   return m_model;
00266 }
00267 
00268 void ExpandingDelegate::heightChanged() const {
00269 }
00270 
00271 bool ExpandingDelegate::editorEvent ( QEvent * event, QAbstractItemModel * /*model*/, const QStyleOptionViewItem & /*option*/, const QModelIndex & index )
00272 {
00273   QKeyEvent* keyEvent = 0;
00274   if( event->type() == QEvent::KeyPress )
00275     keyEvent = reinterpret_cast<QKeyEvent*>(event);
00276   
00277   if( event->type() == QEvent::MouseButtonRelease )
00278   {
00279     event->accept();
00280     model()->setExpanded(index, !model()->isExpanded( index ));
00281     heightChanged();
00282 
00283     return true;
00284   } else {
00285     event->ignore();
00286   }
00287   
00288   return false;
00289 }
00290 
00291 QList<QTextLayout::FormatRange> ExpandingDelegate::highlightingFromVariantList(const QList<QVariant>& customHighlights) const
00292 {
00293     QList<QTextLayout::FormatRange> ret;
00294 
00295     for (int i = 0; i + 2 < customHighlights.count(); i += 3) {
00296       if (!customHighlights[i].canConvert(QVariant::Int) || !customHighlights[i+1].canConvert(QVariant::Int) || !customHighlights[i+2].canConvert<QTextFormat>()) {
00297         kWarning() << "Unable to convert triple to custom formatting.";
00298         continue;
00299       }
00300 
00301       QTextLayout::FormatRange format;
00302       format.start = customHighlights[i].toInt();
00303       format.length = customHighlights[i+1].toInt();
00304       format.format = customHighlights[i+2].value<QTextFormat>().toCharFormat();
00305 
00306       if(!format.format.isValid())
00307         kWarning() << "Format is not valid";
00308 
00309       ret << format;
00310     }
00311     return ret;
00312 }
00313 
00314 #include "expandingdelegate.moc"

Kate

Skip menu "Kate"
  • 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