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