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