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