00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020
00021 #include <qtimer.h>
00022 #include <qpainter.h>
00023 #include <qpixmapcache.h>
00024 #include <qcleanuphandler.h>
00025
00026 #include "kiconview.h"
00027 #include "kwordwrap.h"
00028 #include <kconfig.h>
00029 #include <kdebug.h>
00030 #include <kglobal.h>
00031 #include <kglobalsettings.h>
00032 #include <kapplication.h>
00033
00034 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00035 #include <kipc.h>
00036 #endif
00037
00038 #include <kcursor.h>
00039 #include <kpixmap.h>
00040 #include <kpixmapeffect.h>
00041
00042 class KIconView::KIconViewPrivate
00043 {
00044 public:
00045 KIconViewPrivate() {
00046 mode = KIconView::Execute;
00047 fm = 0L;
00048 doAutoSelect = true;
00049 textHeight = 0;
00050 dragHoldItem = 0L;
00051 }
00052 KIconView::Mode mode;
00053 bool doAutoSelect;
00054 QFontMetrics *fm;
00055 QPixmapCache maskCache;
00056 int textHeight;
00057 QIconViewItem *dragHoldItem;
00058 QTimer dragHoldTimer;
00059 };
00060
00061 KIconView::KIconView( QWidget *parent, const char *name, WFlags f )
00062 : QIconView( parent, name, f )
00063 {
00064 d = new KIconViewPrivate;
00065
00066 connect( this, SIGNAL( onViewport() ),
00067 this, SLOT( slotOnViewport() ) );
00068 connect( this, SIGNAL( onItem( QIconViewItem * ) ),
00069 this, SLOT( slotOnItem( QIconViewItem * ) ) );
00070 slotSettingsChanged( KApplication::SETTINGS_MOUSE );
00071 if ( kapp ) {
00072 connect( kapp, SIGNAL( settingsChanged(int) ), SLOT( slotSettingsChanged(int) ) );
00073 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00074 kapp->addKipcEventMask( KIPC::SettingsChanged );
00075 #endif
00076 }
00077
00078 m_pCurrentItem = 0L;
00079
00080 m_pAutoSelect = new QTimer( this );
00081 connect( m_pAutoSelect, SIGNAL( timeout() ),
00082 this, SLOT( slotAutoSelect() ) );
00083
00084 connect( &d->dragHoldTimer, SIGNAL(timeout()), this, SLOT(slotDragHoldTimeout()) );
00085 }
00086
00087 KIconView::~KIconView()
00088 {
00089 delete d->fm;
00090 delete d;
00091 }
00092
00093
00094 void KIconView::setMode( KIconView::Mode mode )
00095 {
00096 d->mode = mode;
00097 }
00098
00099 KIconView::Mode KIconView::mode() const
00100 {
00101 return d->mode;
00102 }
00103
00104 void KIconView::slotOnItem( QIconViewItem *item )
00105 {
00106 if ( item ) {
00107 if ( m_bUseSingle ) {
00108 if ( m_bChangeCursorOverItem )
00109 viewport()->setCursor( KCursor().handCursor() );
00110
00111 if ( (m_autoSelectDelay > -1) ) {
00112 m_pAutoSelect->start( m_autoSelectDelay, true );
00113 }
00114 }
00115 m_pCurrentItem = item;
00116 }
00117 }
00118
00119 void KIconView::slotOnViewport()
00120 {
00121 if ( m_bUseSingle && m_bChangeCursorOverItem )
00122 viewport()->unsetCursor();
00123
00124 m_pAutoSelect->stop();
00125 m_pCurrentItem = 0L;
00126 }
00127
00128 void KIconView::slotSettingsChanged(int category)
00129 {
00130 if ( category != KApplication::SETTINGS_MOUSE )
00131 return;
00132 m_bUseSingle = KGlobalSettings::singleClick();
00133
00134
00135 disconnect( this, SIGNAL( mouseButtonClicked( int, QIconViewItem *,
00136 const QPoint & ) ),
00137 this, SLOT( slotMouseButtonClicked( int, QIconViewItem *,
00138 const QPoint & ) ) );
00139
00140
00141
00142
00143
00144 if( m_bUseSingle ) {
00145 connect( this, SIGNAL( mouseButtonClicked( int, QIconViewItem *,
00146 const QPoint & ) ),
00147 this, SLOT( slotMouseButtonClicked( int, QIconViewItem *,
00148 const QPoint & ) ) );
00149 }
00150 else {
00151
00152
00153
00154
00155 }
00156
00157 m_bChangeCursorOverItem = KGlobalSettings::changeCursorOverIcon();
00158 m_autoSelectDelay = m_bUseSingle ? KGlobalSettings::autoSelectDelay() : -1;
00159
00160 if( !m_bUseSingle || !m_bChangeCursorOverItem )
00161 viewport()->unsetCursor();
00162 }
00163
00164 void KIconView::slotAutoSelect()
00165 {
00166
00167 if( index( m_pCurrentItem ) == -1 || !d->doAutoSelect )
00168 return;
00169
00170
00171 if( !hasFocus() )
00172 setFocus();
00173
00174 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00175
00176 uint keybstate = KApplication::keyboardModifiers();
00177 QIconViewItem* previousItem = currentItem();
00178 #endif
00179 setCurrentItem( m_pCurrentItem );
00180
00181 if( m_pCurrentItem ) {
00182
00183 #if defined Q_WS_X11 && ! defined K_WS_QTONLY //FIXME
00184 if( (keybstate & KApplication::ShiftModifier) ) {
00185
00186 bool block = signalsBlocked();
00187 blockSignals( true );
00188
00189
00190 if( !(keybstate & KApplication::ControlModifier) )
00191 clearSelection();
00192
00193 bool select = !m_pCurrentItem->isSelected();
00194 bool update = viewport()->isUpdatesEnabled();
00195 viewport()->setUpdatesEnabled( false );
00196
00197
00198
00199 QRect r;
00200 QRect redraw;
00201 if ( previousItem )
00202 r = QRect( QMIN( previousItem->x(), m_pCurrentItem->x() ),
00203 QMIN( previousItem->y(), m_pCurrentItem->y() ),
00204 0, 0 );
00205 else
00206 r = QRect( 0, 0, 0, 0 );
00207 if ( previousItem->x() < m_pCurrentItem->x() )
00208 r.setWidth( m_pCurrentItem->x() - previousItem->x() + m_pCurrentItem->width() );
00209 else
00210 r.setWidth( previousItem->x() - m_pCurrentItem->x() + previousItem->width() );
00211 if ( previousItem->y() < m_pCurrentItem->y() )
00212 r.setHeight( m_pCurrentItem->y() - previousItem->y() + m_pCurrentItem->height() );
00213 else
00214 r.setHeight( previousItem->y() - m_pCurrentItem->y() + previousItem->height() );
00215 r = r.normalize();
00216
00217
00218
00219 for( QIconViewItem* i = firstItem(); i; i = i->nextItem() ) {
00220 if( i->intersects( r ) ) {
00221 redraw = redraw.unite( i->rect() );
00222 setSelected( i, select, true );
00223 }
00224 }
00225
00226 blockSignals( block );
00227 viewport()->setUpdatesEnabled( update );
00228 repaintContents( redraw, false );
00229
00230 emit selectionChanged();
00231
00232 if( selectionMode() == QIconView::Single )
00233 emit selectionChanged( m_pCurrentItem );
00234
00235
00236 }
00237 else if( (keybstate & KApplication::ControlModifier) )
00238 setSelected( m_pCurrentItem, !m_pCurrentItem->isSelected(), true );
00239 else
00240 #endif
00241 setSelected( m_pCurrentItem, true );
00242 }
00243 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00244
00245 else
00246 kdDebug() << "KIconView: That's not supposed to happen!!!!" << endl;
00247 #endif
00248 }
00249
00250 void KIconView::emitExecute( QIconViewItem *item, const QPoint &pos )
00251 {
00252 if ( d->mode != Execute )
00253 {
00254
00255 return;
00256 }
00257
00258 #if defined Q_WS_X11 && ! defined K_WS_QTONLY //FIXME
00259 uint keybstate = KApplication::keyboardModifiers();
00260 #endif
00261
00262 m_pAutoSelect->stop();
00263
00264
00265 #if defined Q_WS_X11 && ! defined K_WS_QTONLY //FIXME
00266 if( !( m_bUseSingle && ((keybstate & KApplication::ShiftModifier) || (keybstate & KApplication::ControlModifier)) ) ) {
00267 setSelected( item, false );
00268 viewport()->unsetCursor();
00269 emit executed( item );
00270 emit executed( item, pos );
00271 }
00272 #endif
00273 }
00274
00275 void KIconView::focusOutEvent( QFocusEvent *fe )
00276 {
00277 m_pAutoSelect->stop();
00278
00279 QIconView::focusOutEvent( fe );
00280 }
00281
00282 void KIconView::leaveEvent( QEvent *e )
00283 {
00284 m_pAutoSelect->stop();
00285
00286 QIconView::leaveEvent( e );
00287 }
00288
00289 void KIconView::contentsMousePressEvent( QMouseEvent *e )
00290 {
00291 if( (selectionMode() == Extended) && (e->state() & ShiftButton) && !(e->state() & ControlButton) ) {
00292 bool block = signalsBlocked();
00293 blockSignals( true );
00294
00295 clearSelection();
00296
00297 blockSignals( block );
00298 }
00299
00300 QIconView::contentsMousePressEvent( e );
00301 d->doAutoSelect = false;
00302 }
00303
00304 void KIconView::contentsMouseDoubleClickEvent ( QMouseEvent * e )
00305 {
00306 QIconView::contentsMouseDoubleClickEvent( e );
00307
00308 QIconViewItem* item = findItem( e->pos() );
00309
00310 if( item ) {
00311 if( (e->button() == LeftButton) && !m_bUseSingle )
00312 emitExecute( item, e->globalPos() );
00313
00314 emit doubleClicked( item, e->globalPos() );
00315 }
00316 }
00317
00318 void KIconView::slotMouseButtonClicked( int btn, QIconViewItem *item, const QPoint &pos )
00319 {
00320
00321 if( (btn == LeftButton) && item )
00322 emitExecute( item, pos );
00323 }
00324
00325 void KIconView::contentsMouseReleaseEvent( QMouseEvent *e )
00326 {
00327 d->doAutoSelect = true;
00328 QIconView::contentsMouseReleaseEvent( e );
00329 }
00330
00331 void KIconView::contentsDragEnterEvent( QDragEnterEvent *e )
00332 {
00333 QIconViewItem *item = findItem( e->pos() );
00334
00335 if ( d->dragHoldItem != item)
00336 {
00337 d->dragHoldItem = item;
00338 if( item != 0L )
00339 {
00340 d->dragHoldTimer.start( 1000, true );
00341 }
00342 else
00343 {
00344 d->dragHoldTimer.stop();
00345 }
00346 }
00347
00348 QIconView::contentsDragEnterEvent( e );
00349 }
00350
00351 void KIconView::contentsDragMoveEvent( QDragMoveEvent *e )
00352 {
00353 QIconViewItem *item = findItem( e->pos() );
00354
00355 if ( d->dragHoldItem != item)
00356 {
00357 d->dragHoldItem = item;
00358 if( item != 0L )
00359 {
00360 d->dragHoldTimer.start( 1000, true );
00361 }
00362 else
00363 {
00364 d->dragHoldTimer.stop();
00365 }
00366 }
00367
00368 QIconView::contentsDragMoveEvent( e );
00369 }
00370
00371 void KIconView::contentsDropEvent( QDropEvent* e )
00372 {
00373 d->dragHoldTimer.stop();
00374 QIconView::contentsDropEvent( e );
00375 }
00376
00377 void KIconView::slotDragHoldTimeout()
00378 {
00379 QIconViewItem *tmp = d->dragHoldItem;
00380 d->dragHoldItem = 0L;
00381
00382 emit held( tmp );
00383 }
00384
00385 void KIconView::wheelEvent( QWheelEvent *e )
00386 {
00387 if (horizontalScrollBar() && (arrangement() == QIconView::TopToBottom)) {
00388 QWheelEvent ce(e->pos(), e->delta(), e->state(), Qt::Horizontal);
00389 QApplication::sendEvent( horizontalScrollBar(), &ce);
00390 if (ce.isAccepted()) {
00391 e->accept();
00392 return;
00393 }
00394 }
00395 QIconView::wheelEvent(e);
00396 }
00397
00398 void KIconView::setFont( const QFont &font )
00399 {
00400 delete d->fm;
00401 d->fm = 0L;
00402 QIconView::setFont( font );
00403 }
00404
00405 QFontMetrics *KIconView::itemFontMetrics() const
00406 {
00407 if (!d->fm) {
00408
00409 d->fm = new QFontMetrics( font() );
00410 }
00411 return d->fm;
00412 }
00413
00414 QPixmap KIconView::selectedIconPixmap( QPixmap *pix, const QColor &col ) const
00415 {
00416 QPixmap m;
00417 if ( d->maskCache.find( QString::number( pix->serialNumber() ), m ) )
00418 return m;
00419 m = KPixmapEffect::selectedPixmap( KPixmap(*pix), col );
00420 d->maskCache.insert( QString::number( pix->serialNumber() ), m );
00421 return m;
00422 }
00423
00424 int KIconView::iconTextHeight() const
00425 {
00426 return d->textHeight > 0 ? d->textHeight : ( wordWrapIconText() ? 99 : 1 );
00427 }
00428
00429 void KIconView::setIconTextHeight( int n )
00430 {
00431 int oldHeight = iconTextHeight();
00432 if ( n > 1 ) {
00433 d->textHeight = n;
00434 setWordWrapIconText( true );
00435 }
00436 else {
00437 d->textHeight = 1;
00438 setWordWrapIconText( false );
00439 }
00440
00441
00442 if ( iconTextHeight() != oldHeight )
00443 setFont( font() );
00444 }
00445
00447
00448 struct KIconViewItem::KIconViewItemPrivate
00449 {
00450 QSize m_pixmapSize;
00451 };
00452
00453 void KIconViewItem::init()
00454 {
00455 m_wordWrap = 0L;
00456 d = 0L;
00457 calcRect();
00458 }
00459
00460 KIconViewItem::~KIconViewItem()
00461 {
00462 delete m_wordWrap;
00463 delete d;
00464 }
00465
00466 void KIconViewItem::calcRect( const QString& text_ )
00467 {
00468 Q_ASSERT( iconView() );
00469 if ( !iconView() )
00470 return;
00471 delete m_wordWrap;
00472 m_wordWrap = 0L;
00473 #ifndef NDEBUG // be faster for the end-user, such a bug will have been fixed before hand :)
00474 if ( !iconView()->inherits("KIconView") )
00475 {
00476 kdWarning() << "KIconViewItem used in a " << iconView()->className() << " !!" << endl;
00477 return;
00478 }
00479 #endif
00480
00481 KIconView *view = static_cast<KIconView *>(iconView());
00482 QRect itemIconRect = pixmapRect();
00483 QRect itemTextRect = textRect();
00484 QRect itemRect = rect();
00485
00486 int pw = 0;
00487 int ph = 0;
00488
00489 #ifndef QT_NO_PICTURE
00490 if ( picture() ) {
00491 QRect br = picture()->boundingRect();
00492 pw = br.width() + 2;
00493 ph = br.height() + 2;
00494 } else
00495 #endif
00496 {
00497
00498 if (!pixmap())
00499 return;
00500 pw = pixmap()->width() + 2;
00501 ph = pixmap()->height() + 2;
00502 }
00503 itemIconRect.setWidth( pw );
00504 #if 1 // FIXME
00505
00506
00507
00508
00509 if ( d && !d->m_pixmapSize.isNull() )
00510 itemIconRect.setHeight( d->m_pixmapSize.height() + 2 );
00511 else
00512 #endif
00513 itemIconRect.setHeight( ph );
00514
00515 int tw = 0;
00516 if ( d && !d->m_pixmapSize.isNull() )
00517 tw = view->maxItemWidth() - ( view->itemTextPos() == QIconView::Bottom ? 0 :
00518 d->m_pixmapSize.width() + 2 );
00519 else
00520 tw = view->maxItemWidth() - ( view->itemTextPos() == QIconView::Bottom ? 0 :
00521 itemIconRect.width() );
00522
00523 QFontMetrics *fm = view->itemFontMetrics();
00524 QString t;
00525 QRect r;
00526
00527
00528 t = text_.isEmpty() ? text() : text_;
00529
00530
00531 int nbLines = static_cast<KIconView*>( iconView() )->iconTextHeight();
00532 int height = nbLines > 0 ? fm->height() * nbLines : 0xFFFFFFFF;
00533
00534
00535 if ( view->itemTextPos() != QIconView::Bottom ) {
00536 if ( d && !d->m_pixmapSize.isNull() )
00537 height = QMIN( d->m_pixmapSize.height() + 2, height );
00538 else
00539 height = QMIN( itemIconRect.height(), height );
00540 height = QMAX( height, fm->height() );
00541 }
00542
00543
00544 QRect outerRect( 0, 0, tw - 6, height );
00545 m_wordWrap = KWordWrap::formatText( *fm, outerRect, 0, t );
00546 r = m_wordWrap->boundingRect();
00547
00548 int realWidth = QMAX( QMIN( r.width() + 4, tw ), fm->width( "X" ) );
00549 itemTextRect.setWidth( realWidth );
00550 itemTextRect.setHeight( r.height() );
00551
00552 int w = 0; int h = 0; int y = 0;
00553 if ( view->itemTextPos() == QIconView::Bottom ) {
00554
00555 if ( d && !d->m_pixmapSize.isNull() )
00556 {
00557 w = QMAX( itemTextRect.width(), d->m_pixmapSize.width() + 2 );
00558 h = itemTextRect.height() + d->m_pixmapSize.height() + 2 + 1;
00559 #if 0 // FIXME
00560
00561
00562 y = d->m_pixmapSize.height() + 2 - itemIconRect.height();
00563 #endif
00564 }
00565 else {
00566 w = QMAX( itemTextRect.width(), itemIconRect.width() );
00567 h = itemTextRect.height() + itemIconRect.height() + 1;
00568 }
00569
00570 itemRect.setWidth( w );
00571 itemRect.setHeight( h );
00572 int width = QMAX( w, QApplication::globalStrut().width() );
00573 int height = QMAX( h, QApplication::globalStrut().height() );
00574 itemTextRect = QRect( ( width - itemTextRect.width() ) / 2, height - itemTextRect.height(),
00575 itemTextRect.width(), itemTextRect.height() );
00576 itemIconRect = QRect( ( width - itemIconRect.width() ) / 2, y,
00577 itemIconRect.width(), itemIconRect.height() );
00578 } else {
00579
00580 if ( d && !d->m_pixmapSize.isNull() )
00581 {
00582 h = QMAX( itemTextRect.height(), d->m_pixmapSize.height() + 2 );
00583 #if 0 // FIXME
00584
00585
00586 y = ( d->m_pixmapSize.height() + 2 - itemIconRect.height() ) / 2;
00587 #endif
00588 }
00589 else
00590 h = QMAX( itemTextRect.height(), itemIconRect.height() );
00591 w = itemTextRect.width() + itemIconRect.width() + 1;
00592
00593 itemRect.setWidth( w );
00594 itemRect.setHeight( h );
00595 int width = QMAX( w, QApplication::globalStrut().width() );
00596 int height = QMAX( h, QApplication::globalStrut().height() );
00597
00598 itemTextRect = QRect( width - itemTextRect.width(), ( height - itemTextRect.height() ) / 2,
00599 itemTextRect.width(), itemTextRect.height() );
00600 if ( itemIconRect.height() > itemTextRect.height() )
00601 itemIconRect = QRect( 0, ( height - itemIconRect.height() ) / 2,
00602 itemIconRect.width(), itemIconRect.height() );
00603 else
00604 itemIconRect = QRect( 0, QMAX(( fm->height() - itemIconRect.height() ) / 2 + y, 0),
00605 itemIconRect.width(), itemIconRect.height() );
00606 if ( ( itemIconRect.height() <= 20 ) && ( itemTextRect.height() < itemIconRect.height() ) )
00607 {
00608 itemTextRect.setHeight( itemIconRect.height() - 2 );
00609 itemTextRect.setY( itemIconRect.y() );
00610 }
00611 }
00612
00613 if ( itemIconRect != pixmapRect() )
00614 setPixmapRect( itemIconRect );
00615 if ( itemTextRect != textRect() )
00616 setTextRect( itemTextRect );
00617 if ( itemRect != rect() )
00618 setItemRect( itemRect );
00619
00620
00621
00622
00623 }
00624
00625 void KIconViewItem::paintItem( QPainter *p, const QColorGroup &cg )
00626 {
00627 QIconView* view = iconView();
00628 Q_ASSERT( view );
00629 if ( !view )
00630 return;
00631 #ifndef NDEBUG // be faster for the end-user, such a bug will have been fixed before hand :)
00632 if ( !view->inherits("KIconView") )
00633 {
00634 kdWarning() << "KIconViewItem used in a " << view->className() << " !!" << endl;
00635 return;
00636 }
00637 #endif
00638
00639 p->save();
00640
00641 paintPixmap(p, cg);
00642 paintText(p, cg);
00643
00644 p->restore();
00645 }
00646
00647 KWordWrap * KIconViewItem::wordWrap()
00648 {
00649 return m_wordWrap;
00650 }
00651
00652 void KIconViewItem::paintPixmap( QPainter *p, const QColorGroup &cg )
00653 {
00654 KIconView *kview = static_cast<KIconView *>(iconView());
00655
00656 #ifndef QT_NO_PICTURE
00657 if ( picture() ) {
00658 QPicture *pic = picture();
00659 if ( isSelected() ) {
00660
00661 p->fillRect( pixmapRect( false ), QBrush( cg.highlight(), QBrush::Dense4Pattern) );
00662 }
00663 p->drawPicture( x()-pic->boundingRect().x(), y()-pic->boundingRect().y(), *pic );
00664 } else
00665 #endif
00666 {
00667 int iconX = pixmapRect( false ).x();
00668 int iconY = pixmapRect( false ).y();
00669
00670 QPixmap *pix = pixmap();
00671 if ( !pix || pix->isNull() )
00672 return;
00673
00674 #if 1 // FIXME
00675
00676
00677
00678 if ( d && !d->m_pixmapSize.isNull() )
00679 {
00680 int offset = 0;
00681 if ( kview->itemTextPos() == QIconView::Bottom )
00682 offset = d->m_pixmapSize.height() - pix->height();
00683 else
00684 offset = ( d->m_pixmapSize.height() - pix->height() ) / 2;
00685 if ( offset > 0 )
00686 iconY += offset;
00687 }
00688 #endif
00689 if ( isSelected() ) {
00690 QPixmap selectedPix = kview->selectedIconPixmap( pix, cg.highlight() );
00691 p->drawPixmap( iconX, iconY, selectedPix );
00692 } else {
00693 p->drawPixmap( iconX, iconY, *pix );
00694 }
00695 }
00696 }
00697
00698 void KIconViewItem::paintText( QPainter *p, const QColorGroup &cg )
00699 {
00700 int textX = textRect( false ).x() + 2;
00701 int textY = textRect( false ).y();
00702
00703 if ( isSelected() ) {
00704 p->fillRect( textRect( false ), cg.highlight() );
00705 p->setPen( QPen( cg.highlightedText() ) );
00706 } else {
00707 if ( iconView()->itemTextBackground() != NoBrush )
00708 p->fillRect( textRect( false ), iconView()->itemTextBackground() );
00709 p->setPen( cg.text() );
00710 }
00711
00712 int align = iconView()->itemTextPos() == QIconView::Bottom ? AlignHCenter : AlignAuto;
00713 m_wordWrap->drawText( p, textX, textY, align | KWordWrap::Truncate );
00714 }
00715
00716 QSize KIconViewItem::pixmapSize() const
00717 {
00718 return d ? d->m_pixmapSize : QSize( 0, 0 );
00719 }
00720
00721 void KIconViewItem::setPixmapSize( const QSize& size )
00722 {
00723 if ( !d )
00724 d = new KIconViewItemPrivate;
00725
00726 d->m_pixmapSize = size;
00727 }
00728
00729 void KIconView::virtual_hook( int, void* )
00730 { }
00731
00732 #include "kiconview.moc"