00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <qfontmetrics.h>
00023 #include <qkeycode.h>
00024 #include <qlabel.h>
00025 #include <qpainter.h>
00026 #include <qpixmap.h>
00027 #include <qregexp.h>
00028 #include <qtimer.h>
00029 #include <qtooltip.h>
00030
00031 #include <kaction.h>
00032 #include <kapplication.h>
00033 #include <klocale.h>
00034 #include <kfileitem.h>
00035 #include <kglobalsettings.h>
00036 #include <kio/previewjob.h>
00037
00038 #include "kfileiconview.h"
00039 #include "config-kfile.h"
00040
00041
00042 KFileIconViewItem::~KFileIconViewItem()
00043 {
00044 fileInfo()->removeExtraData( iconView() );
00045 }
00046
00047 class KFileIconView::KFileIconViewPrivate
00048 {
00049 public:
00050 KFileIconViewPrivate( KFileIconView *parent ) {
00051 previewIconSize = 60;
00052 job = 0L;
00053
00054 noArrangement = false;
00055 smallColumns = new KRadioAction( i18n("Small Icons"), 0, parent,
00056 SLOT( slotSmallColumns() ),
00057 parent->actionCollection(),
00058 "small columns" );
00059
00060 largeRows = new KRadioAction( i18n("Large Icons"), 0, parent,
00061 SLOT( slotLargeRows() ),
00062 parent->actionCollection(),
00063 "large rows" );
00064
00065 smallColumns->setExclusiveGroup(QString::fromLatin1("IconView mode"));
00066 largeRows->setExclusiveGroup(QString::fromLatin1("IconView mode"));
00067
00068 previews = new KToggleAction( i18n("Thumbnail Previews"), 0,
00069 parent->actionCollection(),
00070 "show previews" );
00071 connect( previews, SIGNAL( toggled( bool )),
00072 parent, SLOT( slotPreviewsToggled( bool )));
00073
00074 previewTimer = new QTimer;
00075 connect( previewTimer, SIGNAL( timeout() ),
00076 parent, SLOT( showPreviews() ));
00077 }
00078
00079 ~KFileIconViewPrivate() {
00080 delete previewTimer;
00081 if ( job )
00082 job->kill();
00083 }
00084
00085 KRadioAction *smallColumns, *largeRows;
00086 KToggleAction *previews;
00087 KIO::PreviewJob *job;
00088 QTimer *previewTimer;
00089 QStringList previewMimeTypes;
00090 int previewIconSize;
00091 bool noArrangement :1;
00092 };
00093
00094 KFileIconView::KFileIconView(QWidget *parent, const char *name)
00095 : KIconView(parent, name), KFileView()
00096 {
00097 d = new KFileIconViewPrivate( this );
00098
00099 setViewName( i18n("Icon View") );
00100
00101 toolTip = 0;
00102 setResizeMode( Adjust );
00103 setGridX( 160 );
00104 setWordWrapIconText( false );
00105 setArrangement( TopToBottom );
00106 setAutoArrange( true );
00107 setItemsMovable( false );
00108 setMode( KIconView::Select );
00109 KIconView::setSorting( true );
00110
00111
00112 setShowToolTips( false );
00113 slotSmallColumns();
00114 d->smallColumns->setChecked( true );
00115
00116 connect( this, SIGNAL( returnPressed(QIconViewItem *) ),
00117 SLOT( slotActivate( QIconViewItem *) ) );
00118
00119
00120 connect( this, SIGNAL( clicked(QIconViewItem *, const QPoint&) ),
00121 SLOT( selected( QIconViewItem *) ) );
00122 connect( this, SIGNAL( doubleClicked(QIconViewItem *, const QPoint&) ),
00123 SLOT( slotActivate( QIconViewItem *) ) );
00124
00125 connect( this, SIGNAL( onItem( QIconViewItem * ) ),
00126 SLOT( showToolTip( QIconViewItem * ) ) );
00127 connect( this, SIGNAL( onViewport() ),
00128 SLOT( removeToolTip() ) );
00129 connect( this, SIGNAL( contextMenuRequested(QIconViewItem*,const QPoint&)),
00130 SLOT( slotActivateMenu( QIconViewItem*, const QPoint& ) ) );
00131
00132 KFile::SelectionMode sm = KFileView::selectionMode();
00133 switch ( sm ) {
00134 case KFile::Multi:
00135 QIconView::setSelectionMode( QIconView::Multi );
00136 break;
00137 case KFile::Extended:
00138 QIconView::setSelectionMode( QIconView::Extended );
00139 break;
00140 case KFile::NoSelection:
00141 QIconView::setSelectionMode( QIconView::NoSelection );
00142 break;
00143 default:
00144 case KFile::Single:
00145 QIconView::setSelectionMode( QIconView::Single );
00146 break;
00147 }
00148
00149 if ( sm == KFile::Multi || sm == KFile::Extended )
00150 connect( this, SIGNAL( selectionChanged() ),
00151 SLOT( slotSelectionChanged() ));
00152 else
00153 connect( this, SIGNAL( selectionChanged( QIconViewItem * )),
00154 SLOT( highlighted( QIconViewItem * )));
00155
00156 viewport()->installEventFilter( this );
00157
00158
00159 m_resolver = new KMimeTypeResolver<KFileIconViewItem,KFileIconView>(this);
00160 }
00161
00162 KFileIconView::~KFileIconView()
00163 {
00164 delete m_resolver;
00165 removeToolTip();
00166 delete d;
00167 }
00168
00169 void KFileIconView::readConfig( KConfig *kc, const QString& group )
00170 {
00171 QString gr = group.isEmpty() ? QString("KFileIconView") : group;
00172 KConfigGroupSaver cs( kc, gr );
00173 QString small = QString::fromLatin1("SmallColumns");
00174 d->previewIconSize = kc->readNumEntry( "Preview Size", 60 );
00175 d->previews->setChecked( kc->readBoolEntry( "ShowPreviews", false ) );
00176
00177 if ( kc->readEntry("ViewMode", small ) == small ) {
00178 d->smallColumns->setChecked( true );
00179 slotSmallColumns();
00180 }
00181 else {
00182 d->largeRows->setChecked( true );
00183 slotLargeRows();
00184 }
00185
00186 if ( d->previews->isChecked() )
00187 showPreviews();
00188 }
00189
00190 void KFileIconView::writeConfig( KConfig *kc, const QString& group )
00191 {
00192 QString gr = group.isEmpty() ? QString("KFileIconView") : group;
00193 KConfigGroupSaver cs( kc, gr );
00194 kc->writeEntry( "ViewMode", d->smallColumns->isChecked() ?
00195 QString::fromLatin1("SmallColumns") :
00196 QString::fromLatin1("LargeRows") );
00197 kc->writeEntry( "Preview Size", d->previewIconSize );
00198 kc->writeEntry( "ShowPreviews", d->previews->isChecked() );
00199 }
00200
00201 void KFileIconView::removeToolTip()
00202 {
00203 delete toolTip;
00204 toolTip = 0;
00205 }
00206
00207 void KFileIconView::showToolTip( QIconViewItem *item )
00208 {
00209 delete toolTip;
00210 toolTip = 0;
00211
00212 if ( !item )
00213 return;
00214
00215 int w = maxItemWidth() - ( itemTextPos() == QIconView::Bottom ? 0 :
00216 item->pixmapRect().width() ) - 4;
00217 if ( fontMetrics().width( item->text() ) >= w ) {
00218 toolTip = new QLabel( QString::fromLatin1(" %1 ").arg(item->text()), 0,
00219 "myToolTip",
00220 WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WX11BypassWM );
00221 toolTip->setFrameStyle( QFrame::Plain | QFrame::Box );
00222 toolTip->setLineWidth( 1 );
00223 toolTip->setAlignment( AlignLeft | AlignTop );
00224 toolTip->move( QCursor::pos() + QPoint( 14, 14 ) );
00225 toolTip->adjustSize();
00226 QRect screen = QApplication::desktop()->screenGeometry(
00227 QApplication::desktop()->screenNumber(QCursor::pos()));
00228 if (toolTip->x()+toolTip->width() > screen.right()) {
00229 toolTip->move(toolTip->x()+screen.right()-toolTip->x()-toolTip->width(), toolTip->y());
00230 }
00231 if (toolTip->y()+toolTip->height() > screen.bottom()) {
00232 toolTip->move(toolTip->x(), screen.bottom()-toolTip->y()-toolTip->height()+toolTip->y());
00233 }
00234 toolTip->setFont( QToolTip::font() );
00235 toolTip->setPalette( QToolTip::palette(), TRUE );
00236 toolTip->show();
00237 }
00238 }
00239
00240 void KFileIconView::slotActivateMenu( QIconViewItem* item, const QPoint& pos )
00241 {
00242 if ( !item ) {
00243 sig->activateMenu( 0, pos );
00244 return;
00245 }
00246 KFileIconViewItem *i = (KFileIconViewItem*) item;
00247 sig->activateMenu( i->fileInfo(), pos );
00248 }
00249
00250 void KFileIconView::hideEvent( QHideEvent *e )
00251 {
00252 removeToolTip();
00253 KIconView::hideEvent( e );
00254 }
00255
00256 void KFileIconView::keyPressEvent( QKeyEvent *e )
00257 {
00258 KIconView::keyPressEvent( e );
00259
00260
00261 if ( (e->state() & ControlButton) &&
00262 (e->key() == Key_Return || e->key() == Key_Enter) )
00263 e->ignore();
00264 }
00265
00266 void KFileIconView::setSelected( const KFileItem *info, bool enable )
00267 {
00268 KFileIconViewItem *item = viewItem( info );
00269 if ( item )
00270 KIconView::setSelected( item, enable, true );
00271 }
00272
00273 void KFileIconView::selectAll()
00274 {
00275 if (KFileView::selectionMode() == KFile::NoSelection ||
00276 KFileView::selectionMode() == KFile::Single)
00277 return;
00278
00279 KIconView::selectAll( true );
00280 }
00281
00282 void KFileIconView::clearSelection()
00283 {
00284 KIconView::clearSelection();
00285 }
00286
00287 void KFileIconView::invertSelection()
00288 {
00289 KIconView::invertSelection();
00290 }
00291
00292 void KFileIconView::clearView()
00293 {
00294 m_resolver->m_lstPendingMimeIconItems.clear();
00295
00296 KIconView::clear();
00297 stopPreview();
00298 }
00299
00300 void KFileIconView::insertItem( KFileItem *i )
00301 {
00302 KFileView::insertItem( i );
00303
00304 KFileIconViewItem *item =
00305 new KFileIconViewItem( (QIconView*)this, i->text(),
00306 i->pixmap( iconSizeFor( i ) ), i);
00307 initItem( item, i, false );
00308
00309 if ( !i->isMimeTypeKnown() )
00310 m_resolver->m_lstPendingMimeIconItems.append( item );
00311
00312 i->setExtraData( this, item );
00313 }
00314
00315 void KFileIconView::slotActivate( QIconViewItem *item )
00316 {
00317 if ( !item )
00318 return;
00319 const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
00320 if ( fi )
00321 sig->activate( fi );
00322 }
00323
00324 void KFileIconView::selected( QIconViewItem *item )
00325 {
00326 if ( !item )
00327 return;
00328
00329 if ( KGlobalSettings::singleClick() ) {
00330 const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
00331 if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) )
00332 sig->activate( fi );
00333 }
00334 }
00335
00336 void KFileIconView::setCurrentItem( const KFileItem *item )
00337 {
00338 KFileIconViewItem *it = viewItem( item );
00339 if ( it )
00340 KIconView::setCurrentItem( it );
00341 }
00342
00343 KFileItem * KFileIconView::currentFileItem() const
00344 {
00345 KFileIconViewItem *current = static_cast<KFileIconViewItem*>( currentItem() );
00346 if ( current )
00347 return current->fileInfo();
00348
00349 return 0L;
00350 }
00351
00352 void KFileIconView::highlighted( QIconViewItem *item )
00353 {
00354 if ( !item )
00355 return;
00356 const KFileItem *fi = ( (KFileIconViewItem*)item )->fileInfo();
00357 if ( fi )
00358 sig->highlightFile( fi );
00359 }
00360
00361 void KFileIconView::setSelectionMode( KFile::SelectionMode sm )
00362 {
00363 disconnect( this, SIGNAL( selectionChanged() ));
00364 disconnect( this, SIGNAL( selectionChanged( QIconViewItem * )));
00365
00366 KFileView::setSelectionMode( sm );
00367 switch ( KFileView::selectionMode() ) {
00368 case KFile::Multi:
00369 QIconView::setSelectionMode( QIconView::Multi );
00370 break;
00371 case KFile::Extended:
00372 QIconView::setSelectionMode( QIconView::Extended );
00373 break;
00374 case KFile::NoSelection:
00375 QIconView::setSelectionMode( QIconView::NoSelection );
00376 break;
00377 default:
00378 case KFile::Single:
00379 QIconView::setSelectionMode( QIconView::Single );
00380 break;
00381 }
00382
00383 if ( sm == KFile::Multi || sm == KFile::Extended )
00384 connect( this, SIGNAL( selectionChanged() ),
00385 SLOT( slotSelectionChanged() ));
00386 else
00387 connect( this, SIGNAL( selectionChanged( QIconViewItem * )),
00388 SLOT( highlighted( QIconViewItem * )));
00389 }
00390
00391 bool KFileIconView::isSelected( const KFileItem *i ) const
00392 {
00393 KFileIconViewItem *item = viewItem( i );
00394 return (item && item->isSelected());
00395 }
00396
00397 void KFileIconView::updateView( bool b )
00398 {
00399 if ( !b )
00400 return;
00401
00402 KFileIconViewItem *item = static_cast<KFileIconViewItem*>(QIconView::firstItem());
00403 if ( item ) {
00404 if ( d->previews->isChecked() ) {
00405 do {
00406 int size = canPreview( item->fileInfo() ) ?
00407 d->previewIconSize : myIconSize;
00408 item ->setPixmap( (item->fileInfo())->pixmap( size ) );
00409 item = static_cast<KFileIconViewItem *>(item->nextItem());
00410 } while ( item != 0L );
00411 }
00412
00413 else {
00414 do {
00415 item ->setPixmap( (item->fileInfo())->pixmap( myIconSize));
00416 item = static_cast<KFileIconViewItem *>(item->nextItem());
00417 } while ( item != 0L );
00418 }
00419 }
00420 }
00421
00422 void KFileIconView::updateView( const KFileItem *i )
00423 {
00424 KFileIconViewItem *item = viewItem( i );
00425 if ( item )
00426 initItem( item, i, true );
00427 }
00428
00429 void KFileIconView::removeItem( const KFileItem *i )
00430 {
00431 if ( !i )
00432 return;
00433
00434 KFileIconViewItem *item = viewItem( i );
00435 m_resolver->m_lstPendingMimeIconItems.remove( item );
00436 delete item;
00437
00438 KFileView::removeItem( i );
00439 }
00440
00441 void KFileIconView::setIconSize( int size )
00442 {
00443 myIconSize = size;
00444 updateIcons();
00445 }
00446
00447 void KFileIconView::setPreviewSize( int size )
00448 {
00449 d->previewIconSize = size;
00450 if ( d->previews->isChecked() )
00451 updateIcons();
00452 }
00453
00454 void KFileIconView::updateIcons()
00455 {
00456 updateView( true );
00457 arrangeItemsInGrid();
00458 }
00459
00460 void KFileIconView::ensureItemVisible( const KFileItem *i )
00461 {
00462 KFileIconViewItem *item = viewItem( i );
00463 if ( item )
00464 KIconView::ensureItemVisible( item );
00465 }
00466
00467 void KFileIconView::slotSelectionChanged()
00468 {
00469 sig->highlightFile( 0L );
00470 }
00471
00472 void KFileIconView::slotSmallColumns()
00473 {
00474
00475
00476 d->noArrangement = true;
00477
00478
00479 if ( d->previews->isChecked() )
00480 {
00481 stopPreview();
00482 d->previews->setChecked( false );
00483 }
00484 setGridX( 160 );
00485 setItemTextPos( Right );
00486 setArrangement( TopToBottom );
00487 setWordWrapIconText( false );
00488 setSpacing( 0 );
00489
00490 d->noArrangement = false;
00491 setIconSize( KIcon::SizeSmall );
00492 }
00493
00494 void KFileIconView::slotLargeRows()
00495 {
00496
00497
00498 d->noArrangement = true;
00499
00500 setGridX( KGlobal::iconLoader()->currentSize( KIcon::Desktop ) + 50 );
00501 setItemTextPos( Bottom );
00502 setArrangement( LeftToRight );
00503 setWordWrapIconText( true );
00504 setSpacing( 5 );
00505
00506 d->noArrangement = false;
00507 setIconSize( KIcon::SizeMedium );
00508 }
00509
00510 void KFileIconView::stopPreview()
00511 {
00512 if ( d->job ) {
00513 d->job->kill();
00514 d->job = 0L;
00515 }
00516 }
00517
00518 void KFileIconView::slotPreviewsToggled( bool on )
00519 {
00520 if ( on )
00521 showPreviews();
00522 else {
00523 stopPreview();
00524 slotLargeRows();
00525 }
00526 }
00527
00528 void KFileIconView::showPreviews()
00529 {
00530 if ( d->previewMimeTypes.isEmpty() )
00531 d->previewMimeTypes = KIO::PreviewJob::supportedMimeTypes();
00532
00533 stopPreview();
00534 d->previews->setChecked( true );
00535
00536 if ( !d->largeRows->isChecked() ) {
00537 d->largeRows->setChecked( true );
00538 slotLargeRows();
00539 }
00540 else {
00541 updateIcons();
00542 }
00543
00544 d->job = KIO::filePreview(*items(), d->previewIconSize,d->previewIconSize);
00545
00546 connect( d->job, SIGNAL( result( KIO::Job * )),
00547 this, SLOT( slotPreviewResult( KIO::Job * )));
00548 connect( d->job, SIGNAL( gotPreview( const KFileItem*, const QPixmap& )),
00549 SLOT( gotPreview( const KFileItem*, const QPixmap& ) ));
00550
00551
00552 }
00553
00554 void KFileIconView::slotPreviewResult( KIO::Job *job )
00555 {
00556 if ( job == d->job )
00557 d->job = 0L;
00558 }
00559
00560 void KFileIconView::gotPreview( const KFileItem *item, const QPixmap& pix )
00561 {
00562 KFileIconViewItem *it = viewItem( item );
00563 if ( it )
00564 it->setPixmap( pix );
00565 }
00566
00567 bool KFileIconView::canPreview( const KFileItem *item ) const
00568 {
00569 QStringList::Iterator it = d->previewMimeTypes.begin();
00570 QRegExp r;
00571 r.setWildcard( true );
00572
00573 for ( ; it != d->previewMimeTypes.end(); ++it ) {
00574 QString type = *it;
00575
00576 if ( type.at( type.length() - 1 ) == '*' ) {
00577 r.setPattern( type );
00578 if ( r.search( item->mimetype() ) != -1 )
00579 return true;
00580 }
00581 else
00582 if ( item->mimetype() == type )
00583 return true;
00584 }
00585
00586 return false;
00587 }
00588
00589 KFileItem * KFileIconView::firstFileItem() const
00590 {
00591 KFileIconViewItem *item = static_cast<KFileIconViewItem*>( firstItem() );
00592 if ( item )
00593 return item->fileInfo();
00594 return 0L;
00595 }
00596
00597 KFileItem * KFileIconView::nextItem( const KFileItem *fileItem ) const
00598 {
00599 if ( fileItem ) {
00600 KFileIconViewItem *item = viewItem( fileItem );
00601 if ( item && item->nextItem() )
00602 return ((KFileIconViewItem*) item->nextItem())->fileInfo();
00603 }
00604 return 0L;
00605 }
00606
00607 KFileItem * KFileIconView::prevItem( const KFileItem *fileItem ) const
00608 {
00609 if ( fileItem ) {
00610 KFileIconViewItem *item = viewItem( fileItem );
00611 if ( item && item->prevItem() )
00612 return ((KFileIconViewItem*) item->prevItem())->fileInfo();
00613 }
00614 return 0L;
00615 }
00616
00617 void KFileIconView::setSorting( QDir::SortSpec spec )
00618 {
00619 KFileView::setSorting( spec );
00620 KFileItemListIterator it( *items() );
00621
00622 KFileItem *item;
00623
00624 if ( spec & QDir::Time ) {
00625 for ( ; (item = it.current()); ++it )
00626 viewItem(item)->setKey( sortingKey( item->time( KIO::UDS_MODIFICATION_TIME ), item->isDir(), spec ));
00627 }
00628
00629 else if ( spec & QDir::Size ) {
00630 for ( ; (item = it.current()); ++it )
00631 viewItem(item)->setKey( sortingKey( item->size(), item->isDir(),
00632 spec ));
00633 }
00634 else {
00635 for ( ; (item = it.current()); ++it )
00636 viewItem(item)->setKey( sortingKey( item->text(), item->isDir(),
00637 spec ));
00638 }
00639
00640 KIconView::setSorting( true, !isReversed() );
00641 sort( !isReversed() );
00642 }
00643
00644
00645
00646
00647 void KFileIconView::mimeTypeDeterminationFinished()
00648 {
00649
00650 }
00651
00652 void KFileIconView::determineIcon( KFileIconViewItem *item )
00653 {
00654 (void) item->fileInfo()->determineMimeType();
00655 updateView( item->fileInfo() );
00656 }
00657
00658 void KFileIconView::listingCompleted()
00659 {
00660
00661
00662 if ( !currentItem() ) {
00663 bool block = signalsBlocked();
00664 blockSignals( true );
00665 QIconViewItem *item = viewItem( firstFileItem() );
00666 KIconView::setCurrentItem( item );
00667 KIconView::setSelected( item, false );
00668 blockSignals( block );
00669 }
00670
00671 arrangeItemsInGrid();
00672 m_resolver->start( d->previews->isChecked() ? 0 : 10 );
00673 }
00674
00675
00676 bool KFileIconView::eventFilter( QObject *o, QEvent *e )
00677 {
00678 if ( o == viewport() || o == this ) {
00679 int type = e->type();
00680 if ( type == QEvent::Leave ||
00681 type == QEvent::FocusOut )
00682 removeToolTip();
00683 }
00684
00685 return KIconView::eventFilter( o, e );
00686 }
00687
00689
00690
00691 void KFileIconView::showEvent( QShowEvent *e )
00692 {
00693 KIconView::showEvent( e );
00694 #if QT_VERSION <= 302
00695 sort( !isReversed() );
00696 #endif
00697 }
00698
00699
00700 void KFileIconView::initItem( KFileIconViewItem *item, const KFileItem *i,
00701 bool updateTextAndPixmap )
00702 {
00703 if ( updateTextAndPixmap )
00704 {
00705
00706
00707
00708 item->setText( i->text() , false, false );
00709 item->setPixmap( i->pixmap( iconSizeFor( i ) ) );
00710 }
00711
00712
00713 QDir::SortSpec spec = KFileView::sorting();
00714
00715 if ( spec & QDir::Time )
00716 item->setKey( sortingKey( i->time( KIO::UDS_MODIFICATION_TIME ),
00717 i->isDir(), spec ));
00718 else if ( spec & QDir::Size )
00719 item->setKey( sortingKey( i->size(), i->isDir(), spec ));
00720
00721 else
00722 item->setKey( sortingKey( i->text(), i->isDir(), spec ));
00723
00724
00725
00726 if ( d->previews->isChecked() )
00727 d->previewTimer->start( 10, true );
00728 }
00729
00730 void KFileIconView::arrangeItemsInGrid( bool update )
00731 {
00732 if ( d->noArrangement )
00733 return;
00734
00735 KIconView::arrangeItemsInGrid( update );
00736 }
00737
00738 int KFileIconView::iconSizeFor( const KFileItem *item ) const
00739 {
00740 if ( d->previews->isChecked() && canPreview( item ) )
00741 return d->previewIconSize;
00742 return myIconSize;
00743 }
00744
00745 void KFileIconView::virtual_hook( int id, void* data )
00746 { KIconView::virtual_hook( id, data );
00747 KFileView::virtual_hook( id, data ); }
00748
00749 #include "kfileiconview.moc"