00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <qevent.h>
00023 #include <qkeycode.h>
00024 #include <qheader.h>
00025 #include <qpainter.h>
00026 #include <qpixmap.h>
00027
00028 #include <kapplication.h>
00029 #include <kfileitem.h>
00030 #include <kglobal.h>
00031 #include <kglobalsettings.h>
00032 #include <kiconloader.h>
00033 #include <kicontheme.h>
00034 #include <klocale.h>
00035 #include <kdebug.h>
00036 #include <kurldrag.h>
00037 #include <kdesktopfile.h>
00038
00039 #include "kfiledetailview.h"
00040 #include "config-kfile.h"
00041
00042 #define COL_NAME 0
00043 #define COL_SIZE 1
00044 #define COL_DATE 2
00045 #define COL_PERM 3
00046 #define COL_OWNER 4
00047 #define COL_GROUP 5
00048
00049 class KFileDetailView::KFileDetailViewPrivate
00050 {
00051 public:
00052 KFileDetailViewPrivate() : dropItem(0)
00053 { }
00054
00055 KFileListViewItem *dropItem;
00056 QTimer autoOpenTimer;
00057 };
00058
00059 KFileDetailView::KFileDetailView(QWidget *parent, const char *name)
00060 : KListView(parent, name), KFileView(), d(new KFileDetailViewPrivate())
00061 {
00062
00063 m_sortingCol = COL_NAME;
00064 m_blockSortingSignal = false;
00065 setViewName( i18n("Detailed View") );
00066
00067 addColumn( i18n( "Name" ) );
00068 addColumn( i18n( "Size" ) );
00069 addColumn( i18n( "Date" ) );
00070 addColumn( i18n( "Permissions" ) );
00071 addColumn( i18n( "Owner" ) );
00072 addColumn( i18n( "Group" ) );
00073 setShowSortIndicator( true );
00074 setAllColumnsShowFocus( true );
00075 setDragEnabled(true);
00076
00077 connect( header(), SIGNAL( clicked(int)),
00078 SLOT(slotSortingChanged(int) ));
00079
00080
00081 connect( this, SIGNAL( returnPressed(QListViewItem *) ),
00082 SLOT( slotActivate( QListViewItem *) ) );
00083
00084 connect( this, SIGNAL( clicked(QListViewItem *, const QPoint&, int)),
00085 SLOT( selected( QListViewItem *) ) );
00086 connect( this, SIGNAL( doubleClicked(QListViewItem *, const QPoint&, int)),
00087 SLOT( slotActivate( QListViewItem *) ) );
00088
00089 connect( this, SIGNAL(contextMenuRequested( QListViewItem *,
00090 const QPoint &, int )),
00091 this, SLOT( slotActivateMenu( QListViewItem *, const QPoint& )));
00092
00093 KFile::SelectionMode sm = KFileView::selectionMode();
00094 switch ( sm ) {
00095 case KFile::Multi:
00096 QListView::setSelectionMode( QListView::Multi );
00097 break;
00098 case KFile::Extended:
00099 QListView::setSelectionMode( QListView::Extended );
00100 break;
00101 case KFile::NoSelection:
00102 QListView::setSelectionMode( QListView::NoSelection );
00103 break;
00104 default:
00105 case KFile::Single:
00106 QListView::setSelectionMode( QListView::Single );
00107 break;
00108 }
00109
00110
00111 if ( sm == KFile::Multi || sm == KFile::Extended )
00112 connect( this, SIGNAL( selectionChanged() ),
00113 SLOT( slotSelectionChanged() ));
00114 else
00115 connect( this, SIGNAL( selectionChanged( QListViewItem * ) ),
00116 SLOT( highlighted( QListViewItem * ) ));
00117
00118
00119 connect( &(d->autoOpenTimer), SIGNAL( timeout() ),
00120 this, SLOT( slotAutoOpen() ));
00121
00122 setSorting( sorting() );
00123
00124 m_resolver =
00125 new KMimeTypeResolver<KFileListViewItem,KFileDetailView>( this );
00126 }
00127
00128 KFileDetailView::~KFileDetailView()
00129 {
00130 delete m_resolver;
00131 delete d;
00132 }
00133
00134 void KFileDetailView::readConfig( KConfig *config, const QString& group )
00135 {
00136 restoreLayout( config, group );
00137 }
00138
00139 void KFileDetailView::writeConfig( KConfig *config, const QString& group )
00140 {
00141 saveLayout( config, group );
00142 }
00143
00144 void KFileDetailView::setSelected( const KFileItem *info, bool enable )
00145 {
00146 if ( !info )
00147 return;
00148
00149
00150 KFileListViewItem *item = (KFileListViewItem*)info->extraData( this );
00151
00152 if ( item )
00153 KListView::setSelected( item, enable );
00154 }
00155
00156 void KFileDetailView::setCurrentItem( const KFileItem *item )
00157 {
00158 if ( !item )
00159 return;
00160 KFileListViewItem *it = (KFileListViewItem*) item->extraData( this );
00161 if ( it )
00162 KListView::setCurrentItem( it );
00163 }
00164
00165 KFileItem * KFileDetailView::currentFileItem() const
00166 {
00167 KFileListViewItem *current = static_cast<KFileListViewItem*>( currentItem() );
00168 if ( current )
00169 return current->fileInfo();
00170
00171 return 0L;
00172 }
00173
00174 void KFileDetailView::clearSelection()
00175 {
00176 KListView::clearSelection();
00177 }
00178
00179 void KFileDetailView::selectAll()
00180 {
00181 if (KFileView::selectionMode() == KFile::NoSelection ||
00182 KFileView::selectionMode() == KFile::Single)
00183 return;
00184
00185 KListView::selectAll( true );
00186 }
00187
00188 void KFileDetailView::invertSelection()
00189 {
00190 KListView::invertSelection();
00191 }
00192
00193 void KFileDetailView::slotActivateMenu (QListViewItem *item,const QPoint& pos )
00194 {
00195 if ( !item ) {
00196 sig->activateMenu( 0, pos );
00197 return;
00198 }
00199 KFileListViewItem *i = (KFileListViewItem*) item;
00200 sig->activateMenu( i->fileInfo(), pos );
00201 }
00202
00203 void KFileDetailView::clearView()
00204 {
00205 m_resolver->m_lstPendingMimeIconItems.clear();
00206 KListView::clear();
00207 }
00208
00209 void KFileDetailView::insertItem( KFileItem *i )
00210 {
00211 KFileView::insertItem( i );
00212
00213 if ( i->mimetype() == "application/x-desktop" )
00214 {
00215 KDesktopFile df( i->url().path(), true );
00216 if ( df.readType() == "Link" )
00217 {
00218 i->setName( df.readName() );
00219 }
00220 }
00221
00222 KFileListViewItem *item = new KFileListViewItem( (QListView*) this, i );
00223
00224 setSortingKey( item, i );
00225
00226 i->setExtraData( this, item );
00227
00228 if ( !i->isMimeTypeKnown() )
00229 m_resolver->m_lstPendingMimeIconItems.append( item );
00230 }
00231
00232 void KFileDetailView::slotActivate( QListViewItem *item )
00233 {
00234 if ( !item )
00235 return;
00236
00237 const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
00238
00239 if ( fi->mimetype() == "application/x-desktop" )
00240 {
00241 KDesktopFile df( fi->url().path(), true );
00242 if ( df.readType() == "Link" )
00243 {
00244 KURL lu( df.readURL() );
00245 if ( lu.isLocalFile() )
00246 {
00247 fi = new KFileItem( KURL( df.readURL() ), "inode/directory", S_IFDIR );
00248 }
00249 }
00250 }
00251
00252 if ( fi )
00253 sig->activate( fi );
00254 }
00255
00256 void KFileDetailView::selected( QListViewItem *item )
00257 {
00258 if ( !item )
00259 return;
00260
00261 const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
00262 if ( fi->mimetype() == "application/x-desktop" )
00263 {
00264 KDesktopFile df( fi->url().path(), true );
00265 if ( df.readType() == "Link" )
00266 {
00267 KURL lu( df.readURL() );
00268 if ( lu.isLocalFile() )
00269 {
00270 fi = new KFileItem( KURL( df.readURL() ), "inode/directory", S_IFDIR );
00271 }
00272 }
00273 }
00274
00275 if ( KGlobalSettings::singleClick() )
00276 {
00277 if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) )
00278 sig->activate( fi );
00279 }
00280 }
00281
00282 void KFileDetailView::highlighted( QListViewItem *item )
00283 {
00284 if ( !item )
00285 return;
00286
00287 const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
00288 if ( fi )
00289 sig->highlightFile( fi );
00290 }
00291
00292
00293 void KFileDetailView::setSelectionMode( KFile::SelectionMode sm )
00294 {
00295 disconnect( this, SIGNAL( selectionChanged() ));
00296 disconnect( this, SIGNAL( selectionChanged( QListViewItem * ) ));
00297
00298 KFileView::setSelectionMode( sm );
00299
00300 switch ( KFileView::selectionMode() ) {
00301 case KFile::Multi:
00302 QListView::setSelectionMode( QListView::Multi );
00303 break;
00304 case KFile::Extended:
00305 QListView::setSelectionMode( QListView::Extended );
00306 break;
00307 case KFile::NoSelection:
00308 QListView::setSelectionMode( QListView::NoSelection );
00309 break;
00310 default:
00311 case KFile::Single:
00312 QListView::setSelectionMode( QListView::Single );
00313 break;
00314 }
00315
00316 if ( sm == KFile::Multi || sm == KFile::Extended )
00317 connect( this, SIGNAL( selectionChanged() ),
00318 SLOT( slotSelectionChanged() ));
00319 else
00320 connect( this, SIGNAL( selectionChanged( QListViewItem * )),
00321 SLOT( highlighted( QListViewItem * )));
00322 }
00323
00324 bool KFileDetailView::isSelected( const KFileItem *i ) const
00325 {
00326 if ( !i )
00327 return false;
00328
00329 KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
00330 return (item && item->isSelected());
00331 }
00332
00333
00334 void KFileDetailView::updateView( bool b )
00335 {
00336 if ( !b )
00337 return;
00338
00339 QListViewItemIterator it( (QListView*)this );
00340 for ( ; it.current(); ++it ) {
00341 KFileListViewItem *item=static_cast<KFileListViewItem *>(it.current());
00342 item->setPixmap( 0, item->fileInfo()->pixmap(KIcon::SizeSmall) );
00343 }
00344 }
00345
00346 void KFileDetailView::updateView( const KFileItem *i )
00347 {
00348 if ( !i )
00349 return;
00350
00351 KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
00352 if ( !item )
00353 return;
00354
00355 item->init();
00356 setSortingKey( item, i );
00357
00358
00359 }
00360
00361 void KFileDetailView::setSortingKey( KFileListViewItem *item,
00362 const KFileItem *i )
00363 {
00364
00365 QDir::SortSpec spec = KFileView::sorting();
00366
00367 if ( spec & QDir::Time )
00368 item->setKey( sortingKey( i->time( KIO::UDS_MODIFICATION_TIME ),
00369 i->isDir(), spec ));
00370 else if ( spec & QDir::Size )
00371 item->setKey( sortingKey( i->size(), i->isDir(), spec ));
00372
00373 else
00374 item->setKey( sortingKey( i->text(), i->isDir(), spec ));
00375 }
00376
00377
00378 void KFileDetailView::removeItem( const KFileItem *i )
00379 {
00380 if ( !i )
00381 return;
00382
00383 KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
00384 m_resolver->m_lstPendingMimeIconItems.remove( item );
00385 delete item;
00386
00387 KFileView::removeItem( i );
00388 }
00389
00390 void KFileDetailView::slotSortingChanged( int col )
00391 {
00392
00393
00394 QDir::SortSpec sort = sorting();
00395 int sortSpec = -1;
00396 bool reversed = (col == m_sortingCol) && (sort & QDir::Reversed) == 0;
00397 m_sortingCol = col;
00398
00399 switch( col ) {
00400 case COL_NAME:
00401 sortSpec = (sort & ~QDir::SortByMask | QDir::Name);
00402 break;
00403 case COL_SIZE:
00404 sortSpec = (sort & ~QDir::SortByMask | QDir::Size);
00405 break;
00406 case COL_DATE:
00407 sortSpec = (sort & ~QDir::SortByMask | QDir::Time);
00408 break;
00409
00410
00411
00412 case COL_OWNER:
00413 case COL_GROUP:
00414 case COL_PERM:
00415
00416 sortSpec = (sort & ~QDir::SortByMask);
00417 break;
00418 default:
00419 break;
00420 }
00421
00422 if ( reversed )
00423 sortSpec |= QDir::Reversed;
00424 else
00425 sortSpec &= ~QDir::Reversed;
00426
00427 if ( sort & QDir::IgnoreCase )
00428 sortSpec |= QDir::IgnoreCase;
00429 else
00430 sortSpec &= ~QDir::IgnoreCase;
00431
00432
00433 KFileView::setSorting( static_cast<QDir::SortSpec>( sortSpec ) );
00434
00435 KFileItem *item;
00436 KFileItemListIterator it( *items() );
00437
00438 if ( sortSpec & QDir::Time ) {
00439 for ( ; (item = it.current()); ++it )
00440 viewItem(item)->setKey( sortingKey( item->time( KIO::UDS_MODIFICATION_TIME ), item->isDir(), sortSpec ));
00441 }
00442
00443 else if ( sortSpec & QDir::Size ) {
00444 for ( ; (item = it.current()); ++it )
00445 viewItem(item)->setKey( sortingKey( item->size(), item->isDir(),
00446 sortSpec ));
00447 }
00448 else {
00449 for ( ; (item = it.current()); ++it ) {
00450 KFileListViewItem *i = viewItem( item );
00451 i->setKey( sortingKey( i->text(m_sortingCol), item->isDir(),
00452 sortSpec ));
00453 }
00454 }
00455
00456 KListView::setSorting( m_sortingCol, !reversed );
00457 KListView::sort();
00458
00459 if ( !m_blockSortingSignal )
00460 sig->changeSorting( static_cast<QDir::SortSpec>( sortSpec ) );
00461 }
00462
00463
00464 void KFileDetailView::setSorting( QDir::SortSpec spec )
00465 {
00466 int col = 0;
00467 if ( spec & QDir::Time )
00468 col = COL_DATE;
00469 else if ( spec & QDir::Size )
00470 col = COL_SIZE;
00471 else if ( spec & QDir::Unsorted )
00472 col = m_sortingCol;
00473 else
00474 col = COL_NAME;
00475
00476
00477 if ( spec & QDir::Reversed )
00478 spec = (QDir::SortSpec) (spec & ~QDir::Reversed);
00479 else
00480 spec = (QDir::SortSpec) (spec | QDir::Reversed);
00481
00482 m_sortingCol = col;
00483 KFileView::setSorting( (QDir::SortSpec) spec );
00484
00485
00486
00487 m_blockSortingSignal = true;
00488 slotSortingChanged( col );
00489 m_blockSortingSignal = false;
00490 }
00491
00492 void KFileDetailView::ensureItemVisible( const KFileItem *i )
00493 {
00494 if ( !i )
00495 return;
00496
00497 KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
00498
00499 if ( item )
00500 KListView::ensureItemVisible( item );
00501 }
00502
00503
00504 void KFileDetailView::slotSelectionChanged()
00505 {
00506 sig->highlightFile( 0L );
00507 }
00508
00509 KFileItem * KFileDetailView::firstFileItem() const
00510 {
00511 KFileListViewItem *item = static_cast<KFileListViewItem*>( firstChild() );
00512 if ( item )
00513 return item->fileInfo();
00514 return 0L;
00515 }
00516
00517 KFileItem * KFileDetailView::nextItem( const KFileItem *fileItem ) const
00518 {
00519 if ( fileItem ) {
00520 KFileListViewItem *item = viewItem( fileItem );
00521 if ( item && item->itemBelow() )
00522 return ((KFileListViewItem*) item->itemBelow())->fileInfo();
00523 else
00524 return 0L;
00525 }
00526 else
00527 return firstFileItem();
00528 }
00529
00530 KFileItem * KFileDetailView::prevItem( const KFileItem *fileItem ) const
00531 {
00532 if ( fileItem ) {
00533 KFileListViewItem *item = viewItem( fileItem );
00534 if ( item && item->itemAbove() )
00535 return ((KFileListViewItem*) item->itemAbove())->fileInfo();
00536 else
00537 return 0L;
00538 }
00539 else
00540 return firstFileItem();
00541 }
00542
00543 void KFileDetailView::keyPressEvent( QKeyEvent *e )
00544 {
00545 KListView::keyPressEvent( e );
00546
00547 if ( e->key() == Key_Return || e->key() == Key_Enter ) {
00548 if ( e->state() & ControlButton )
00549 e->ignore();
00550 else
00551 e->accept();
00552 }
00553 }
00554
00555
00556
00557
00558 void KFileDetailView::mimeTypeDeterminationFinished()
00559 {
00560
00561 }
00562
00563 void KFileDetailView::determineIcon( KFileListViewItem *item )
00564 {
00565 (void) item->fileInfo()->determineMimeType();
00566 updateView( item->fileInfo() );
00567 }
00568
00569 void KFileDetailView::listingCompleted()
00570 {
00571 m_resolver->start();
00572 }
00573
00574 QDragObject *KFileDetailView::dragObject()
00575 {
00576
00577 KURL::List urls;
00578 KFileItemListIterator it( * KFileView::selectedItems() );
00579 for ( ; it.current(); ++it ){
00580 urls.append( (*it)->url() );
00581 }
00582 QPixmap pixmap;
00583 if( urls.count() > 1 )
00584 pixmap = DesktopIcon( "kmultiple", KIcon::SizeSmall );
00585 if( pixmap.isNull() )
00586 pixmap = currentFileItem()->pixmap( KIcon::SizeSmall );
00587
00588 QPoint hotspot;
00589 hotspot.setX( pixmap.width() / 2 );
00590 hotspot.setY( pixmap.height() / 2 );
00591 QDragObject* myDragObject = new KURLDrag( urls, widget() );
00592 myDragObject->setPixmap( pixmap, hotspot );
00593 return myDragObject;
00594 }
00595
00596 void KFileDetailView::slotAutoOpen()
00597 {
00598 d->autoOpenTimer.stop();
00599 if( !d->dropItem )
00600 return;
00601
00602 KFileItem *fileItem = d->dropItem->fileInfo();
00603 if (!fileItem)
00604 return;
00605
00606 if( fileItem->isFile() )
00607 return;
00608
00609 if ( fileItem->isDir() || fileItem->isLink())
00610 sig->activate( fileItem );
00611 }
00612
00613 bool KFileDetailView::acceptDrag(QDropEvent* e) const
00614 {
00615 return KURLDrag::canDecode( e ) &&
00616 (e->source()!= const_cast<KFileDetailView*>(this)) &&
00617 ( e->action() == QDropEvent::Copy
00618 || e->action() == QDropEvent::Move
00619 || e->action() == QDropEvent::Link );
00620 }
00621
00622 void KFileDetailView::contentsDragEnterEvent( QDragEnterEvent *e )
00623 {
00624 if ( ! acceptDrag( e ) ) {
00625 e->ignore();
00626 return;
00627 }
00628 e->acceptAction();
00629
00630 if ((dropOptions() & AutoOpenDirs) == 0)
00631 return;
00632
00633 KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
00634 if ( item ) {
00635 d->dropItem = item;
00636 d->autoOpenTimer.start( autoOpenDelay() );
00637 }
00638 else
00639 {
00640 d->dropItem = 0;
00641 d->autoOpenTimer.stop();
00642 }
00643 }
00644
00645 void KFileDetailView::contentsDragMoveEvent( QDragMoveEvent *e )
00646 {
00647 if ( ! acceptDrag( e ) ) {
00648 e->ignore();
00649 return;
00650 }
00651 e->acceptAction();
00652
00653 if ((dropOptions() & AutoOpenDirs) == 0)
00654 return;
00655
00656 KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
00657 if ( item ) {
00658 if (d->dropItem != item)
00659 {
00660 d->dropItem = item;
00661 d->autoOpenTimer.start( autoOpenDelay() );
00662 }
00663 }
00664 else
00665 {
00666 d->dropItem = 0;
00667 d->autoOpenTimer.stop();
00668 }
00669 }
00670
00671 void KFileDetailView::contentsDragLeaveEvent( QDragLeaveEvent * )
00672 {
00673 d->dropItem = 0;
00674 d->autoOpenTimer.stop();
00675 }
00676
00677 void KFileDetailView::contentsDropEvent( QDropEvent *e )
00678 {
00679 d->dropItem = 0;
00680 d->autoOpenTimer.stop();
00681
00682 if ( ! acceptDrag( e ) ) {
00683 e->ignore();
00684 return;
00685 }
00686 e->acceptAction();
00687
00688 KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
00689 KFileItem * fileItem = 0;
00690 if (item)
00691 fileItem = item->fileInfo();
00692
00693 emit dropped(e, fileItem);
00694
00695 KURL::List urls;
00696 if (KURLDrag::decode( e, urls ) && !urls.isEmpty())
00697 {
00698 emit dropped(e, urls, fileItem ? fileItem->url() : KURL());
00699 sig->dropURLs(fileItem, e, urls);
00700 }
00701 }
00702
00703
00705
00706
00707 void KFileListViewItem::init()
00708 {
00709 KFileListViewItem::setPixmap( COL_NAME, inf->pixmap(KIcon::SizeSmall));
00710
00711 setText( COL_NAME, inf->text() );
00712 setText( COL_SIZE, KGlobal::locale()->formatNumber( inf->size(), 0));
00713 setText( COL_DATE, inf->timeString() );
00714 setText( COL_PERM, inf->permissionsString() );
00715 setText( COL_OWNER, inf->user() );
00716 setText( COL_GROUP, inf->group() );
00717 }
00718
00719
00720 void KFileDetailView::virtual_hook( int id, void* data )
00721 { KListView::virtual_hook( id, data );
00722 KFileView::virtual_hook( id, data ); }
00723
00724 #include "kfiledetailview.moc"