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