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