00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <qtimer.h>
00019 #include <qpainter.h>
00020 #include <qpixmapcache.h>
00021 #include <qcleanuphandler.h>
00022
00023 #include "kiconview.h"
00024 #include "kwordwrap.h"
00025 #include <kconfig.h>
00026 #include <kdebug.h>
00027 #include <kglobal.h>
00028 #include <kglobalsettings.h>
00029 #include <kapplication.h>
00030 #include <kipc.h>
00031 #include <kcursor.h>
00032 #include <kpixmap.h>
00033 #include <kpixmapeffect.h>
00034
00035 #ifdef Q_WS_X11
00036 #include <X11/Xlib.h>
00037 #endif
00038
00039 class KIconView::KIconViewPrivate
00040 {
00041 public:
00042 KIconViewPrivate() {
00043 mode = KIconView::Execute;
00044 fm = 0L;
00045 doAutoSelect = true;
00046 }
00047 KIconView::Mode mode;
00048 bool doAutoSelect;
00049 QFontMetrics *fm;
00050 QPixmapCache maskCache;
00051 };
00052
00053 KIconView::KIconView( QWidget *parent, const char *name, WFlags f )
00054 : QIconView( parent, name, f )
00055 {
00056 d = new KIconViewPrivate;
00057
00058 connect( this, SIGNAL( onViewport() ),
00059 this, SLOT( slotOnViewport() ) );
00060 connect( this, SIGNAL( onItem( QIconViewItem * ) ),
00061 this, SLOT( slotOnItem( QIconViewItem * ) ) );
00062 slotSettingsChanged( KApplication::SETTINGS_MOUSE );
00063 if ( kapp ) {
00064 connect( kapp, SIGNAL( settingsChanged(int) ), SLOT( slotSettingsChanged(int) ) );
00065 kapp->addKipcEventMask( KIPC::SettingsChanged );
00066 }
00067
00068 m_pCurrentItem = 0L;
00069
00070 m_pAutoSelect = new QTimer( this );
00071 connect( m_pAutoSelect, SIGNAL( timeout() ),
00072 this, SLOT( slotAutoSelect() ) );
00073 }
00074
00075 KIconView::~KIconView()
00076 {
00077 delete d->fm;
00078 delete d;
00079 }
00080
00081
00082 void KIconView::setMode( KIconView::Mode mode )
00083 {
00084 d->mode = mode;
00085 }
00086
00087 KIconView::Mode KIconView::mode() const
00088 {
00089 return d->mode;
00090 }
00091
00092 void KIconView::slotOnItem( QIconViewItem *item )
00093 {
00094 if ( item ) {
00095 if ( m_bUseSingle ) {
00096 if ( m_bChangeCursorOverItem )
00097 viewport()->setCursor( KCursor().handCursor() );
00098
00099 if ( (m_autoSelectDelay > -1) ) {
00100 m_pAutoSelect->start( m_autoSelectDelay, true );
00101 }
00102 }
00103 m_pCurrentItem = item;
00104 }
00105 }
00106
00107 void KIconView::slotOnViewport()
00108 {
00109 if ( m_bUseSingle && m_bChangeCursorOverItem )
00110 viewport()->unsetCursor();
00111
00112 m_pAutoSelect->stop();
00113 m_pCurrentItem = 0L;
00114 }
00115
00116 void KIconView::slotSettingsChanged(int category)
00117 {
00118 if ( category != KApplication::SETTINGS_MOUSE )
00119 return;
00120 m_bUseSingle = KGlobalSettings::singleClick();
00121
00122
00123 disconnect( this, SIGNAL( mouseButtonClicked( int, QIconViewItem *,
00124 const QPoint & ) ),
00125 this, SLOT( slotMouseButtonClicked( int, QIconViewItem *,
00126 const QPoint & ) ) );
00127
00128
00129
00130
00131
00132 if( m_bUseSingle ) {
00133 connect( this, SIGNAL( mouseButtonClicked( int, QIconViewItem *,
00134 const QPoint & ) ),
00135 this, SLOT( slotMouseButtonClicked( int, QIconViewItem *,
00136 const QPoint & ) ) );
00137 }
00138 else {
00139
00140
00141
00142
00143 }
00144
00145 m_bChangeCursorOverItem = KGlobalSettings::changeCursorOverIcon();
00146 m_autoSelectDelay = m_bUseSingle ? KGlobalSettings::autoSelectDelay() : -1;
00147
00148 if( !m_bUseSingle || !m_bChangeCursorOverItem )
00149 viewport()->unsetCursor();
00150 }
00151
00152 void KIconView::slotAutoSelect()
00153 {
00154
00155 if( index( m_pCurrentItem ) == -1 || !d->doAutoSelect )
00156 return;
00157
00158
00159 if( !hasFocus() )
00160 setFocus();
00161
00162 #ifdef Q_WS_X11
00163
00164 Window root;
00165 Window child;
00166 int root_x, root_y, win_x, win_y;
00167 uint keybstate;
00168 XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
00169 &root_x, &root_y, &win_x, &win_y, &keybstate );
00170 #endif
00171
00172 QIconViewItem* previousItem = currentItem();
00173 setCurrentItem( m_pCurrentItem );
00174
00175 if( m_pCurrentItem ) {
00176
00177 #ifdef Q_WS_X11 //FIXME
00178 if( (keybstate & ShiftMask) ) {
00179
00180 bool block = signalsBlocked();
00181 blockSignals( true );
00182
00183
00184 if( !(keybstate & ControlMask) )
00185 clearSelection();
00186
00187 bool select = !m_pCurrentItem->isSelected();
00188 bool update = viewport()->isUpdatesEnabled();
00189 viewport()->setUpdatesEnabled( false );
00190
00191
00192
00193 QRect r;
00194 QRect redraw;
00195 if ( previousItem )
00196 r = QRect( QMIN( previousItem->x(), m_pCurrentItem->x() ),
00197 QMIN( previousItem->y(), m_pCurrentItem->y() ),
00198 0, 0 );
00199 else
00200 r = QRect( 0, 0, 0, 0 );
00201 if ( previousItem->x() < m_pCurrentItem->x() )
00202 r.setWidth( m_pCurrentItem->x() - previousItem->x() + m_pCurrentItem->width() );
00203 else
00204 r.setWidth( previousItem->x() - m_pCurrentItem->x() + previousItem->width() );
00205 if ( previousItem->y() < m_pCurrentItem->y() )
00206 r.setHeight( m_pCurrentItem->y() - previousItem->y() + m_pCurrentItem->height() );
00207 else
00208 r.setHeight( previousItem->y() - m_pCurrentItem->y() + previousItem->height() );
00209 r = r.normalize();
00210
00211
00212
00213 for( QIconViewItem* i = firstItem(); i; i = i->nextItem() ) {
00214 if( i->intersects( r ) ) {
00215 redraw = redraw.unite( i->rect() );
00216 setSelected( i, select, true );
00217 }
00218 }
00219
00220 blockSignals( block );
00221 viewport()->setUpdatesEnabled( update );
00222 repaintContents( redraw, false );
00223
00224 emit selectionChanged();
00225
00226 if( selectionMode() == QIconView::Single )
00227 emit selectionChanged( m_pCurrentItem );
00228
00229
00230 }
00231 else if( (keybstate & ControlMask) )
00232 setSelected( m_pCurrentItem, !m_pCurrentItem->isSelected(), true );
00233 else
00234 #endif
00235 setSelected( m_pCurrentItem, true );
00236 }
00237 #ifndef Q_WS_QWS //FIXME: Remove #if as soon as the stuff above is implemented
00238 else
00239 kdDebug() << "KIconView: That's not supposed to happen!!!!" << endl;
00240 #endif
00241 }
00242
00243 void KIconView::emitExecute( QIconViewItem *item, const QPoint &pos )
00244 {
00245 if ( d->mode != Execute )
00246 {
00247
00248 return;
00249 }
00250
00251 #ifdef Q_WS_X11 //FIXME
00252 Window root;
00253 Window child;
00254 int root_x, root_y, win_x, win_y;
00255 uint keybstate;
00256 XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
00257 &root_x, &root_y, &win_x, &win_y, &keybstate );
00258 #endif
00259
00260 m_pAutoSelect->stop();
00261
00262
00263 #ifdef Q_WS_X11 //FIXME
00264 if( !( m_bUseSingle && ((keybstate & ShiftMask) || (keybstate & ControlMask)) ) ) {
00265 setSelected( item, false );
00266 emit executed( item );
00267 emit executed( item, pos );
00268 }
00269 #endif
00270 }
00271
00272 void KIconView::focusOutEvent( QFocusEvent *fe )
00273 {
00274 m_pAutoSelect->stop();
00275
00276 QIconView::focusOutEvent( fe );
00277 }
00278
00279 void KIconView::leaveEvent( QEvent *e )
00280 {
00281 m_pAutoSelect->stop();
00282
00283 QIconView::leaveEvent( e );
00284 }
00285
00286 void KIconView::contentsMousePressEvent( QMouseEvent *e )
00287 {
00288 if( (selectionMode() == Extended) && (e->state() & ShiftButton) && !(e->state() & ControlButton) ) {
00289 bool block = signalsBlocked();
00290 blockSignals( true );
00291
00292 clearSelection();
00293
00294 blockSignals( block );
00295 }
00296
00297 QIconView::contentsMousePressEvent( e );
00298 d->doAutoSelect = FALSE;
00299 }
00300
00301 void KIconView::contentsMouseDoubleClickEvent ( QMouseEvent * e )
00302 {
00303 QIconView::contentsMouseDoubleClickEvent( e );
00304
00305 QIconViewItem* item = findItem( e->pos() );
00306
00307 if( item ) {
00308 if( (e->button() == LeftButton) && !m_bUseSingle )
00309 emitExecute( item, e->globalPos() );
00310
00311 emit doubleClicked( item, e->globalPos() );
00312 }
00313 }
00314
00315 void KIconView::slotMouseButtonClicked( int btn, QIconViewItem *item, const QPoint &pos )
00316 {
00317
00318 if( (btn == LeftButton) && item )
00319 emitExecute( item, pos );
00320 }
00321
00322 void KIconView::contentsMouseReleaseEvent( QMouseEvent *e )
00323 {
00324 d->doAutoSelect = TRUE;
00325 QIconView::contentsMouseReleaseEvent( e );
00326 }
00327
00328 void KIconView::setFont( const QFont &font )
00329 {
00330 delete d->fm;
00331 d->fm = 0L;
00332 QIconView::setFont( font );
00333 }
00334
00335 QFontMetrics *KIconView::itemFontMetrics() const
00336 {
00337 if (!d->fm) {
00338
00339 d->fm = new QFontMetrics( font() );
00340 }
00341 return d->fm;
00342 }
00343
00344 QPixmap KIconView::selectedIconPixmap( QPixmap *pix, const QColor &col ) const
00345 {
00346 QPixmap m;
00347 if ( d->maskCache.find( QString::number( pix->serialNumber() ), m ) )
00348 return m;
00349 m = KPixmapEffect::selectedPixmap( KPixmap(*pix), col );
00350 d->maskCache.insert( QString::number( pix->serialNumber() ), m );
00351 return m;
00352 }
00353
00355
00356 struct KIconViewItem::KIconViewItemPrivate
00357 {
00358 };
00359
00360 void KIconViewItem::init()
00361 {
00362 m_wordWrap = 0L;
00363 d = 0L;
00364 calcRect();
00365 }
00366
00367 KIconViewItem::~KIconViewItem()
00368 {
00369 delete m_wordWrap;
00370 delete d;
00371 }
00372
00373 void KIconViewItem::calcRect( const QString& text_ )
00374 {
00375 Q_ASSERT( iconView() );
00376 if ( !iconView() )
00377 return;
00378 delete m_wordWrap;
00379 m_wordWrap = 0L;
00380
00381 if ( !iconView()->wordWrapIconText() )
00382 {
00383 QIconViewItem::calcRect( text_ );
00384 return;
00385 }
00386 #ifndef NDEBUG // be faster for the end-user, such a bug will have been fixed before hand :)
00387 if ( !iconView()->inherits("KIconView") )
00388 {
00389 kdWarning() << "KIconViewItem used in a " << iconView()->className() << " !!" << endl;
00390 return;
00391 }
00392 #endif
00393
00394 KIconView *view = static_cast<KIconView *>(iconView());
00395 QRect itemIconRect = pixmapRect();
00396 QRect itemTextRect = textRect();
00397 QRect itemRect = rect();
00398
00399 int pw = 0;
00400 int ph = 0;
00401
00402 #ifndef QT_NO_PICTURE
00403 if ( picture() ) {
00404 QRect br = picture()->boundingRect();
00405 pw = br.width() + 2;
00406 ph = br.height() + 2;
00407 } else
00408 #endif
00409 {
00410
00411 if (!pixmap())
00412 return;
00413 pw = pixmap()->width() + 2;
00414 ph = pixmap()->height() + 2;
00415 }
00416 itemIconRect.setWidth( pw );
00417 itemIconRect.setHeight( ph );
00418
00419
00420
00421
00422 QString t = text_.isEmpty() ? text() : text_;
00423
00424 int tw = 0;
00425 int th = 0;
00426 QFontMetrics *fm = view->itemFontMetrics();
00427 QRect outerRect( 0, 0, view->maxItemWidth() -
00428 ( view->itemTextPos() == QIconView::Bottom ? 0 :
00429 pixmapRect().width() ), 0xFFFFFFFF );
00430
00431 m_wordWrap = KWordWrap::formatText( *fm, outerRect, AlignHCenter | WordBreak , t );
00432 QRect r = m_wordWrap->boundingRect();
00433 r.setWidth( r.width() + 4 );
00434
00435
00436 if ( r.width() > view->maxItemWidth() -
00437 ( view->itemTextPos() == QIconView::Bottom ? 0 :
00438 pixmapRect().width() ) )
00439 r.setWidth( view->maxItemWidth() - ( view->itemTextPos() == QIconView::Bottom ? 0 :
00440 pixmapRect().width() ) );
00441
00442 tw = r.width();
00443 th = r.height();
00444 int minw = fm->width( "X" );
00445 if ( tw < minw )
00446 tw = minw;
00447
00448 itemTextRect.setWidth( tw );
00449 itemTextRect.setHeight( th );
00450
00451
00452
00453
00454
00455 int w = 0; int h = 0;
00456 if ( view->itemTextPos() == QIconView::Bottom ) {
00457 w = QMAX( itemTextRect.width(), itemIconRect.width() );
00458 h = itemTextRect.height() + itemIconRect.height() + 1;
00459
00460 itemRect.setWidth( w );
00461 itemRect.setHeight( h );
00462 int width = QMAX( w, QApplication::globalStrut().width() );
00463 int height = QMAX( h, QApplication::globalStrut().height() );
00464 itemTextRect = QRect( ( width - itemTextRect.width() ) / 2, height - itemTextRect.height(),
00465 itemTextRect.width(), itemTextRect.height() );
00466 itemIconRect = QRect( ( width - itemIconRect.width() ) / 2, 0,
00467 itemIconRect.width(), itemIconRect.height() );
00468 } else {
00469 h = QMAX( itemTextRect.height(), itemIconRect.height() );
00470 w = itemTextRect.width() + itemIconRect.width() + 1;
00471
00472 itemRect.setWidth( w );
00473 itemRect.setHeight( h );
00474 int width = QMAX( w, QApplication::globalStrut().width() );
00475 int height = QMAX( h, QApplication::globalStrut().height() );
00476
00477 itemTextRect = QRect( width - itemTextRect.width(), ( height - itemTextRect.height() ) / 2,
00478 itemTextRect.width(), itemTextRect.height() );
00479 if ( itemIconRect.height() > itemTextRect.height() )
00480 itemIconRect = QRect( 0, ( height - itemIconRect.height() ) / 2,
00481 itemIconRect.width(), itemIconRect.height() );
00482 else
00483 itemIconRect = QRect( 0, QMAX(( fm->height() - itemIconRect.height() ) / 2, 0),
00484 itemIconRect.width(), itemIconRect.height() );
00485 }
00486 #if 0
00487 kdDebug() << "KIconViewItem::calcRect itemIconRect=" << itemIconRect.x() << "," << itemIconRect.y()
00488 << " " << itemIconRect.width() << "x" << itemIconRect.height() << endl;
00489 kdDebug() << "KIconViewItem::calcRect itemTextRect=" << itemTextRect.x() << "," << itemTextRect.y()
00490 << " " << itemTextRect.width() << "x" << itemTextRect.height() << endl;
00491 kdDebug() << "KIconViewItem::calcRect itemRect=" << itemRect.x() << "," << itemRect.y()
00492 << " " << itemRect.width() << "x" << itemRect.height() << endl;
00493 kdDebug() << "KIconViewItem::calcRect - DONE" << endl;
00494 #endif
00495
00496 if ( itemIconRect != pixmapRect() )
00497 setPixmapRect( itemIconRect );
00498 if ( itemTextRect != textRect() )
00499 setTextRect( itemTextRect );
00500 if ( itemRect != rect() )
00501 setItemRect( itemRect );
00502
00503
00504
00505
00506 }
00507
00508 void KIconViewItem::paintItem( QPainter *p, const QColorGroup &cg )
00509 {
00510 QIconView* view = iconView();
00511 Q_ASSERT( view );
00512 if ( !view )
00513 return;
00514
00515
00516
00517
00518 if ( !view->wordWrapIconText() )
00519 {
00520 QIconViewItem::paintItem( p, cg );
00521 return;
00522 }
00523 #ifndef NDEBUG // be faster for the end-user, such a bug will have been fixed before hand :)
00524 if ( !view->inherits("KIconView") )
00525 {
00526 kdWarning() << "KIconViewItem used in a " << view->className() << " !!" << endl;
00527 return;
00528 }
00529 #endif
00530 if ( !m_wordWrap )
00531 {
00532 kdWarning() << "KIconViewItem::paintItem called but wordwrap not ready - calcRect not called, or aborted!" << endl;
00533 return;
00534 }
00535 KIconView *kview = static_cast<KIconView *>(iconView());
00536 int textX = textRect( FALSE ).x();
00537 int textY = textRect( FALSE ).y();
00538 int iconX = pixmapRect( FALSE ).x();
00539 int iconY = pixmapRect( FALSE ).y();
00540
00541 p->save();
00542
00543 #ifndef QT_NO_PICTURE
00544 if ( picture() ) {
00545 QPicture *pic = picture();
00546 if ( isSelected() ) {
00547
00548 p->fillRect( pixmapRect( FALSE ), QBrush( cg.highlight(), QBrush::Dense4Pattern) );
00549 }
00550 p->drawPicture( x()-pic->boundingRect().x(), y()-pic->boundingRect().y(), *pic );
00551 } else
00552 #endif
00553 {
00554 QPixmap *pix = pixmap();
00555 if ( isSelected() ) {
00556 if ( pix && !pix->isNull() ) {
00557 QPixmap selectedPix = kview->selectedIconPixmap( pix, cg.highlight() );
00558 p->drawPixmap( iconX, iconY, selectedPix );
00559 }
00560 } else {
00561 p->drawPixmap( iconX, iconY, *pix );
00562 }
00563 }
00564
00565 if ( isSelected() ) {
00566 p->fillRect( textRect( FALSE ), cg.highlight() );
00567 p->setPen( QPen( cg.highlightedText() ) );
00568 } else {
00569 if ( view->itemTextBackground() != NoBrush )
00570 p->fillRect( textRect( FALSE ), view->itemTextBackground() );
00571 p->setPen( cg.text() );
00572 }
00573
00574 int align = view->itemTextPos() == QIconView::Bottom ? AlignHCenter : AlignAuto;
00575 m_wordWrap->drawText( p, textX, textY, align );
00576
00577 p->restore();
00578 }
00579
00580 void KIconView::virtual_hook( int, void* )
00581 { }
00582
00583 #include "kiconview.moc"