F:/KPlato/koffice/libs/kofficeui/KoDocumentSectionDelegate.cpp

Aller à la documentation de ce fichier.
00001 /*
00002   Copyright (c) 2006 Gábor Lehel <illissius@gmail.com>
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 as published by the Free Software Foundation; either
00007   version 2 of the License, or (at your option) any later version.
00008 
00009   This library is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012   Library General Public License for more details.
00013 
00014   You should have received a copy of the GNU Library General Public License
00015   along with this library; see the file COPYING.LIB.  If not, write to
00016   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017   Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <QtDebug>
00021 #include <QApplication>
00022 #include <QKeyEvent>
00023 #include <QLineEdit>
00024 #include <QModelIndex>
00025 #include <QMouseEvent>
00026 #include <QPainter>
00027 #include <QPointer>
00028 #include <QStyleOptionViewItem>
00029 #include "KoDocumentSectionModel.h"
00030 #include "KoDocumentSectionToolTip.h"
00031 #include "KoDocumentSectionView.h"
00032 #include "KoDocumentSectionDelegate.h"
00033 
00034 class KoDocumentSectionDelegate::Private
00035 {
00036     public:
00037         KoDocumentSectionView *view;
00038         QPointer<QWidget> edit;
00039         KoDocumentSectionToolTip tip;
00040         static const int margin = 1;
00041         Private(): view( 0 ), edit( 0 ) { }
00042 };
00043 
00044 KoDocumentSectionDelegate::KoDocumentSectionDelegate( KoDocumentSectionView *view, QObject *parent )
00045     : super( parent )
00046     , d( new Private )
00047 {
00048     d->view = view;
00049     view->setItemDelegate( this );
00050     QApplication::instance()->installEventFilter( this );
00051 }
00052 
00053 KoDocumentSectionDelegate::~KoDocumentSectionDelegate()
00054 {
00055     delete d;
00056 }
00057 
00058 QSize KoDocumentSectionDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const
00059 {
00060     switch( d->view->displayMode() )
00061     {
00062         case View::ThumbnailMode:
00063         {
00064             const int height = thumbnailHeight( option, index ) + textBoxHeight( option ) + d->margin * 2;
00065             return QSize( availableWidth( index ), height );
00066         }
00067         case View::DetailedMode:
00068             return QSize( option.rect.width(),
00069                 textBoxHeight( option ) + option.decorationSize.height() + d->margin );
00070         case View::MinimalMode:
00071             return QSize( option.rect.width(), textBoxHeight( option ) );
00072         default: return option.rect.size(); //gcc--
00073     }
00074 }
00075 
00076 void KoDocumentSectionDelegate::paint( QPainter *p, const QStyleOptionViewItem &o, const QModelIndex &index ) const
00077 {
00078     p->save();
00079     {
00080         QStyleOptionViewItem option = getOptions( o, index );
00081 
00082         p->setFont( option.font );
00083 
00084         if( option.state & QStyle::State_Selected )
00085             p->fillRect( option.rect, option.palette.highlight() );
00086 
00087         drawText( p, option, index );
00088         drawIcons( p, option, index );
00089         drawThumbnail( p, option, index );
00090         drawDecoration( p, option, index );
00091     }
00092     p->restore();
00093 }
00094 
00095 bool KoDocumentSectionDelegate::editorEvent( QEvent *e, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )
00096 {
00097     if( e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick )
00098     {
00099         QMouseEvent *me = static_cast<QMouseEvent*>( e );
00100         if( me->button() != Qt::LeftButton )
00101         {
00102             d->view->setCurrentIndex( index );
00103             return false;
00104         }
00105 
00106         const QRect ir = iconsRect( option, index ).translated( option.rect.topLeft() ),
00107                     tr = textRect( option, index ).translated( option.rect.topLeft() );
00108 
00109         if( ir.isValid() && ir.contains( me->pos() ) )
00110         {
00111             const int iconWidth = option.decorationSize.width();
00112             int x = me->pos().x() - ir.left();
00113             if( x % ( iconWidth + d->margin ) < iconWidth ) //it's on an icon, not a margin
00114             {
00115                 Model::PropertyList lp = index.data( Model::PropertiesRole ).value<Model::PropertyList>();
00116                 int p = -1;
00117                 for( int i = 0, n = lp.count(); i < n; ++i )
00118                 {
00119                     if( lp[i].isMutable )
00120                         x -= iconWidth + d->margin;
00121                     p += 1;
00122                     if( x < 0 )
00123                         break;
00124                 }
00125                 lp[p].state = !lp[p].state.toBool();
00126                 model->setData( index, QVariant::fromValue( lp ), Model::PropertiesRole );
00127             }
00128             return true;
00129         }
00130 
00131         else if( tr.isValid() && tr.contains( me->pos() ) && ( option.state & QStyle::State_HasFocus ) )
00132         {
00133             d->view->edit( index );
00134             return true;
00135         }
00136 
00137         if( !( me->modifiers() & Qt::ControlModifier) && !( me->modifiers() & Qt::ShiftModifier ) )
00138             d->view->setCurrentIndex( index );
00139     }
00140 
00141     else if( e->type() == QEvent::ToolTip )
00142     {
00143         QHelpEvent *he = static_cast<QHelpEvent*>( e );
00144         d->tip.showTip( d->view, he->pos(), option, index );
00145         return true;
00146     }
00147 
00148     else if( e->type() == QEvent::Leave )
00149     {
00150         d->tip.hide();
00151     }
00152 
00153     return false;
00154 }
00155 
00156 QWidget *KoDocumentSectionDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem&, const QModelIndex& ) const
00157 {
00158     d->edit = new QLineEdit( parent );
00159     d->edit->installEventFilter( const_cast<KoDocumentSectionDelegate*>( this ) ); //hack?
00160     return d->edit;
00161 }
00162 
00163 void KoDocumentSectionDelegate::setEditorData( QWidget *widget, const QModelIndex &index ) const
00164 {
00165     QLineEdit *edit = qobject_cast<QLineEdit*>( widget );
00166     Q_ASSERT( edit );
00167 
00168     edit->setText( index.data( Qt::DisplayRole ).toString() );
00169 }
00170 
00171 void KoDocumentSectionDelegate::setModelData( QWidget *widget, QAbstractItemModel *model, const QModelIndex &index ) const
00172 {
00173     QLineEdit *edit = qobject_cast<QLineEdit*>( widget );
00174     Q_ASSERT( edit );
00175 
00176     model->setData( index, edit->text(), Qt::DisplayRole );
00177 }
00178 
00179 void KoDocumentSectionDelegate::updateEditorGeometry( QWidget *widget, const QStyleOptionViewItem &option, const QModelIndex &index ) const
00180 {
00181     widget->setGeometry( textRect( option, index ).translated( option.rect.topLeft() ) );
00182 }
00183 
00184 
00185 // PROTECTED
00186 
00187 
00188 bool KoDocumentSectionDelegate::eventFilter( QObject *object, QEvent *event )
00189 {
00190     if( event->type() == QEvent::MouseButtonPress && d->edit )
00191     {
00192         QMouseEvent *me = static_cast<QMouseEvent*>( event );
00193         if( !QRect( d->edit->mapToGlobal( QPoint() ), d->edit->size() ).contains( me->globalPos() ) )
00194             emit closeEditor( d->edit );
00195     }
00196 
00197     QLineEdit *edit = qobject_cast<QLineEdit*>( object );
00198     if( edit && edit == d->edit && event->type() == QEvent::KeyPress )
00199     {
00200         QKeyEvent *ke = static_cast<QKeyEvent*>( event );
00201         switch( ke->key() )
00202         {
00203             case Qt::Key_Escape:
00204                 emit closeEditor( edit );
00205                 return true;
00206             case Qt::Key_Tab:
00207                 emit commitData( edit );
00208                 emit closeEditor( edit, EditNextItem );
00209                 return true;
00210             case Qt::Key_Backtab:
00211                 emit commitData( edit );
00212                 emit closeEditor( edit, EditPreviousItem );
00213                 return true;
00214             case Qt::Key_Return:
00215             case Qt::Key_Enter:
00216                 emit commitData( edit );
00217                 emit closeEditor( edit );
00218                 return true;
00219             default: break;
00220         }
00221     }
00222 
00223     return super::eventFilter( object, event );
00224 }
00225 
00226 
00227 // PRIVATE
00228 
00229 
00230 QStyleOptionViewItem KoDocumentSectionDelegate::getOptions( const QStyleOptionViewItem &o, const QModelIndex &index )
00231 {
00232     QStyleOptionViewItem option = o;
00233     QVariant v = index.data( Qt::FontRole );
00234     if( v.isValid() )
00235     {
00236         option.font = v.value<QFont>();
00237         option.fontMetrics = QFontMetrics( option.font );
00238     }
00239     v = index.data( Qt::TextAlignmentRole );
00240     if( v.isValid() )
00241         option.displayAlignment = QFlag( v.toInt() );
00242     v = index.data( Qt::TextColorRole );
00243     if( v.isValid() )
00244         option.palette.setColor( QPalette::Text, v.value<QColor>() );
00245     v = index.data( Qt::BackgroundColorRole );
00246     if( v.isValid() )
00247         option.palette.setColor( QPalette::Background, v.value<QColor>() );
00248 
00249    return option;
00250 }
00251 
00252 int KoDocumentSectionDelegate::thumbnailHeight( const QStyleOptionViewItem &option, const QModelIndex &index ) const
00253 {
00254     const QSize size = index.data( Qt::SizeHintRole ).toSize();
00255     int width = option.rect.width();
00256     if( !option.rect.isValid() )
00257         width = availableWidth( index );
00258     if( size.width() <= width )
00259         return size.height();
00260     else
00261         return int( width / ( double( size.width() ) / size.height() ) );
00262 }
00263 
00264 int KoDocumentSectionDelegate::availableWidth( const QModelIndex &index ) const
00265     //this is such a HACK
00266 {
00267     int dis = 0;
00268     if( d->view->rootIndex().isValid() )
00269     {
00270         QModelIndex i = index;
00271         while( i.isValid() && i != d->view->rootIndex() )
00272         {
00273             i = i.parent();
00274             dis++;
00275         }
00276         Q_ASSERT( i.isValid() );
00277     }
00278     if( d->view->rootIsDecorated() )
00279         dis++;
00280     const int indent = dis * d->view->indentation();
00281     return d->view->columnWidth( 0 ) - indent;
00282 }
00283 
00284 int KoDocumentSectionDelegate::textBoxHeight( const QStyleOptionViewItem &option ) const
00285 {
00286     return qMax( option.fontMetrics.height(), option.decorationSize.height() );
00287 }
00288 
00289 QRect KoDocumentSectionDelegate::textRect( const QStyleOptionViewItem &option, const QModelIndex &index ) const
00290 {
00291     if( d->view->displayMode() == View::ThumbnailMode )
00292     {
00293         const QRect r = decorationRect( option, index );
00294         const int left = r.right() + d->margin;
00295         return QRect( left, r.top(), option.rect.width() - left, textBoxHeight( option ) );
00296     }
00297     else
00298     {
00299         static QFont f;
00300         static int minbearing = 1337 + 666; //can be 0 or negative, 2003 is less likely
00301         if( minbearing == 2003 || f != option.font )
00302         {
00303             f = option.font; //getting your bearings can be expensive, so we cache them
00304             minbearing = option.fontMetrics.minLeftBearing() + option.fontMetrics.minRightBearing();
00305         }
00306 
00307         int indent = decorationRect( option, index ).right() + d->margin;
00308 
00309         const int width = ( d->view->displayMode() == View::DetailedMode
00310                             ? option.rect.width()
00311                             : iconsRect( option, index ).left() )
00312                           - indent - d->margin + minbearing;
00313 
00314         return QRect( indent, 0, width, textBoxHeight( option ) );
00315     }
00316 }
00317 
00318 QRect KoDocumentSectionDelegate::iconsRect( const QStyleOptionViewItem &option, const QModelIndex &index ) const
00319 {
00320     if( d->view->displayMode() == View::ThumbnailMode )
00321         return QRect();
00322 
00323     Model::PropertyList lp = index.data( Model::PropertiesRole ).value<Model::PropertyList>();
00324     int propscount = 0;
00325     for( int i = 0, n = lp.count(); i < n; ++i )
00326         if( lp[i].isMutable )
00327             propscount++;
00328 
00329     const int iconswidth = propscount * option.decorationSize.width() + (propscount - 1) * d->margin;
00330 
00331     const int x = d->view->displayMode() == View::DetailedMode ? thumbnailRect( option, index ).right() + d->margin : option.rect.width() - iconswidth;
00332     const int y = d->view->displayMode() == View::DetailedMode ? textBoxHeight( option ) + d->margin : 0;
00333 
00334     return QRect( x, y, iconswidth, option.decorationSize.height() );
00335 }
00336 
00337 QRect KoDocumentSectionDelegate::thumbnailRect( const QStyleOptionViewItem &option, const QModelIndex &index ) const
00338 {
00339     if( d->view->displayMode() == View::ThumbnailMode )
00340         return QRect( 0, 0, option.rect.width(), thumbnailHeight( option, index ) );
00341     else
00342         return QRect( 0, 0, option.rect.height(), option.rect.height() );
00343 }
00344 
00345 QRect KoDocumentSectionDelegate::decorationRect( const QStyleOptionViewItem &option, const QModelIndex &index ) const
00346 {
00347     int width = option.decorationSize.width();
00348     if( index.data( Qt::DecorationRole ).value<QIcon>().isNull() )
00349         width = 0;
00350     switch( d->view->displayMode() )
00351     {
00352         case View::ThumbnailMode:
00353         {
00354             QFont font = option.font;
00355             if( index.data( Model::ActiveRole ).toBool() )
00356                 font.setBold( !font.bold() );
00357             const QFontMetrics metrics( font );
00358             const int totalwidth = metrics.width( index.data( Qt::DisplayRole ).toString() ) + width + d->margin;
00359             int left;
00360             if( totalwidth < option.rect.width() )
00361                 left = ( option.rect.width() - totalwidth ) / 2;
00362             else
00363                 left = 0;
00364             return QRect( left, thumbnailRect( option, index ).bottom() + d->margin, width, textBoxHeight( option ) );
00365         }
00366         case View::DetailedMode:
00367         case View::MinimalMode:
00368         {
00369             const int left = thumbnailRect( option, index ).right() + d->margin;
00370             return QRect( left, 0, width, textBoxHeight( option ) );
00371         }
00372         default: return QRect(); //gcc--
00373     }
00374 }
00375 
00376 void KoDocumentSectionDelegate::drawText( QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index ) const
00377 {
00378     const QRect r = textRect( option, index ).translated( option.rect.topLeft() );
00379 
00380     p->save();
00381     {
00382         p->setClipRect( r );
00383         p->translate( r.left(), r.top() );
00384         p->setPen( ( option.state & QStyle::State_Selected )
00385                    ? option.palette.highlightedText().color()
00386                    : option.palette.text().color() );
00387 
00388         if( index.data( Model::ActiveRole ).toBool() )
00389         {
00390             QFont f = p->font();
00391             f.setBold( !f.bold() );
00392             p->setFont( f );
00393         }
00394 
00395         const QString text = index.data( Qt::DisplayRole ).toString();
00396         const QString elided = elidedText( p->fontMetrics(), r.width(), Qt::ElideRight, text );
00397         p->drawText( d->margin, 0, r.width(), r.height(), Qt::AlignLeft | Qt::AlignTop, elided );
00398     }
00399     p->restore();
00400 }
00401 
00402 void KoDocumentSectionDelegate::drawIcons( QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index ) const
00403 {
00404     const QRect r = iconsRect( option, index ).translated( option.rect.topLeft() );
00405 
00406     p->save();
00407     {
00408         p->setClipRect( r );
00409         p->translate( r.left(), r.top() );
00410         int x = 0;
00411         Model::PropertyList lp = index.data( Model::PropertiesRole ).value<Model::PropertyList>();
00412         for( int i = 0, n = lp.count(); i < n; ++i )
00413             if( lp[i].isMutable )
00414             {
00415                 QIcon icon = lp[i].state.toBool() ? lp[i].onIcon : lp[i].offIcon;
00416                 p->drawPixmap( x, 0, icon.pixmap( option.decorationSize ) );
00417                 x += option.decorationSize.width() + d->margin;
00418             }
00419     }
00420     p->restore();
00421 }
00422 
00423 void KoDocumentSectionDelegate::drawThumbnail( QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index ) const
00424 {
00425     const QRect r = thumbnailRect( option, index ).translated( option.rect.topLeft() );
00426 
00427     p->save();
00428     {
00429         p->setClipRect( r );
00430         const double myratio = double( r.width() ) / r.height();
00431         const double thumbratio = index.data( Model::AspectRatioRole ).toDouble();
00432         const int s = ( myratio > thumbratio ) ? r.height() : r.width();
00433 
00434         const QImage i = index.data( int( Model::BeginThumbnailRole ) + s ).value<QImage>();
00435         QPoint offset;
00436         offset.setX( r.width()/2 - i.width()/2 );
00437         offset.setY( r.height()/2 - i.height()/2 );
00438 
00439         p->drawImage( r.topLeft() + offset, i );
00440     }
00441     p->restore();
00442 }
00443 
00444 void KoDocumentSectionDelegate::drawDecoration( QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index ) const
00445 {
00446     const QRect r = decorationRect( option, index ).translated( option.rect.topLeft() );
00447 
00448     p->save();
00449     {
00450         p->setClipRect( r );
00451         p->translate( r.topLeft() );
00452         if( !index.data( Qt::DecorationRole ).value<QIcon>().isNull() )
00453             p->drawPixmap( 0, 0, index.data( Qt::DecorationRole ).value<QIcon>().pixmap( option.decorationSize ) );
00454     }
00455     p->restore();
00456 }
00457 
00458 
00459 
00460 #include "KoDocumentSectionDelegate.moc"

Généré le Wed Nov 22 23:41:04 2006 pour KPlato par  doxygen 1.5.1-p1