00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <qapplication.h>
00021 #include <qheader.h>
00022 #include <qtimer.h>
00023 #include <kdebug.h>
00024 #include <kdirnotify_stub.h>
00025 #include <kglobalsettings.h>
00026 #include <kfileitem.h>
00027 #include <kfileview.h>
00028 #include <kmimetype.h>
00029 #include <kstandarddirs.h>
00030 #include <stdlib.h>
00031 #include <assert.h>
00032 #include <kio/job.h>
00033 #include <kio/global.h>
00034 #include <kurldrag.h>
00035 #include <kiconloader.h>
00036
00037
00038 #include "kfiletreeview.h"
00039 #include "kfiletreebranch.h"
00040 #include "kfiletreeviewitem.h"
00041
00042 KFileTreeView::KFileTreeView( QWidget *parent, const char *name )
00043 : KListView( parent, name ),
00044 m_wantOpenFolderPixmaps( true ),
00045 m_toolTip( this )
00046 {
00047 setSelectionModeExt( KListView::Single );
00048
00049 m_animationTimer = new QTimer( this );
00050 connect( m_animationTimer, SIGNAL( timeout() ),
00051 this, SLOT( slotAnimation() ) );
00052
00053 m_currentBeforeDropItem = 0;
00054 m_dropItem = 0;
00055
00056 m_autoOpenTimer = new QTimer( this );
00057 connect( m_autoOpenTimer, SIGNAL( timeout() ),
00058 this, SLOT( slotAutoOpenFolder() ) );
00059
00060
00061 connect( this, SIGNAL( executed( QListViewItem * ) ),
00062 this, SLOT( slotExecuted( QListViewItem * ) ) );
00063 connect( this, SIGNAL( expanded ( QListViewItem *) ),
00064 this, SLOT( slotExpanded( QListViewItem *) ));
00065 connect( this, SIGNAL( collapsed( QListViewItem *) ),
00066 this, SLOT( slotCollapsed( QListViewItem* )));
00067
00068
00069
00070 connect( this, SIGNAL( selectionChanged() ),
00071 this, SLOT( slotSelectionChanged() ) );
00072 connect( this, SIGNAL( onItem( QListViewItem * )),
00073 this, SLOT( slotOnItem( QListViewItem * ) ) );
00074 connect( this, SIGNAL(itemRenamed(QListViewItem*, const QString &, int)),
00075 this, SLOT(slotItemRenamed(QListViewItem*, const QString &, int)));
00076
00077
00078 m_bDrag = false;
00079 m_branches.setAutoDelete( true );
00080
00081 m_openFolderPixmap = SmallIcon( "folder_open" );
00082 }
00083
00084 KFileTreeView::~KFileTreeView()
00085 {
00086
00087
00088
00089 hide();
00090 clear();
00091 m_branches.clear();
00092 }
00093
00094
00095 void KFileTreeView::contentsDragEnterEvent( QDragEnterEvent *ev )
00096 {
00097 if ( ! acceptDrag( ev ) )
00098 {
00099 ev->ignore();
00100 return;
00101 }
00102 ev->acceptAction();
00103 m_currentBeforeDropItem = selectedItem();
00104
00105 QListViewItem *item = itemAt( contentsToViewport( ev->pos() ) );
00106 if( item )
00107 {
00108 m_dropItem = item;
00109 m_autoOpenTimer->start( KFileView::autoOpenDelay() );
00110 }
00111 else
00112 {
00113 m_dropItem = 0;
00114 }
00115 }
00116
00117 void KFileTreeView::contentsDragMoveEvent( QDragMoveEvent *e )
00118 {
00119 if( ! acceptDrag( e ) )
00120 {
00121 e->ignore();
00122 return;
00123 }
00124 e->acceptAction();
00125
00126
00127 QListViewItem *afterme;
00128 QListViewItem *parent;
00129
00130 findDrop( e->pos(), parent, afterme );
00131
00132
00133 QListViewItem *item = afterme ? afterme : parent;
00134
00135 if( item && item->isSelectable() )
00136 {
00137 setSelected( item, true );
00138 if( item != m_dropItem ) {
00139 m_autoOpenTimer->stop();
00140 m_dropItem = item;
00141 m_autoOpenTimer->start( KFileView::autoOpenDelay() );
00142 }
00143 }
00144 else
00145 {
00146 m_autoOpenTimer->stop();
00147 m_dropItem = 0;
00148 }
00149 }
00150
00151 void KFileTreeView::contentsDragLeaveEvent( QDragLeaveEvent * )
00152 {
00153
00154 if ( m_currentBeforeDropItem )
00155 {
00156 setSelected( m_currentBeforeDropItem, true );
00157 ensureItemVisible( m_currentBeforeDropItem );
00158 }
00159 else
00160 setSelected( m_dropItem, false );
00161 m_currentBeforeDropItem = 0;
00162 m_dropItem = 0;
00163
00164 }
00165
00166 void KFileTreeView::contentsDropEvent( QDropEvent *e )
00167 {
00168
00169 m_autoOpenTimer->stop();
00170 m_dropItem = 0;
00171
00172 kdDebug(250) << "contentsDropEvent !" << endl;
00173 if( ! acceptDrag( e ) ) {
00174 e->ignore();
00175 return;
00176 }
00177
00178 e->acceptAction();
00179 QListViewItem *afterme;
00180 QListViewItem *parent;
00181 findDrop(e->pos(), parent, afterme);
00182
00183
00184
00185
00186 if (e->source() == viewport() && itemsMovable())
00187 movableDropEvent(parent, afterme);
00188 else
00189 {
00190 emit dropped(e, afterme);
00191 emit dropped(this, e, afterme);
00192 emit dropped(e, parent, afterme);
00193 emit dropped(this, e, parent, afterme);
00194
00195 KURL::List urls;
00196 KURLDrag::decode( e, urls );
00197 emit dropped( this, e, urls );
00198
00199 KURL parentURL;
00200 if( parent )
00201 parentURL = static_cast<KFileTreeViewItem*>(parent)->url();
00202 else
00203
00204
00205 return;
00206
00207 emit dropped( urls, parentURL );
00208 emit dropped( this , e, urls, parentURL );
00209 }
00210 }
00211
00212 bool KFileTreeView::acceptDrag(QDropEvent* e ) const
00213 {
00214
00215 bool ancestOK= acceptDrops();
00216
00217 ancestOK = ancestOK && itemsMovable();
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 return ancestOK && KURLDrag::canDecode( e ) &&
00228
00229 ( e->action() == QDropEvent::Copy
00230 || e->action() == QDropEvent::Move
00231 || e->action() == QDropEvent::Link );
00232 }
00233
00234
00235
00236 QDragObject * KFileTreeView::dragObject()
00237 {
00238
00239 KURL::List urls;
00240 const QPtrList<QListViewItem> fileList = selectedItems();
00241 QPtrListIterator<QListViewItem> it( fileList );
00242 for ( ; it.current(); ++it )
00243 {
00244 urls.append( static_cast<KFileTreeViewItem*>(it.current())->url() );
00245 }
00246 QPoint hotspot;
00247 QPixmap pixmap;
00248 if( urls.count() > 1 ){
00249 pixmap = DesktopIcon( "kmultiple", 16 );
00250 }
00251 if( pixmap.isNull() )
00252 pixmap = currentKFileTreeViewItem()->fileItem()->pixmap( 16 );
00253 hotspot.setX( pixmap.width() / 2 );
00254 hotspot.setY( pixmap.height() / 2 );
00255 QDragObject* dragObject = new KURLDrag( urls, this );
00256 if( dragObject )
00257 dragObject->setPixmap( pixmap, hotspot );
00258 return dragObject;
00259 }
00260
00261
00262
00263 void KFileTreeView::slotCollapsed( QListViewItem *item )
00264 {
00265 KFileTreeViewItem *kftvi = static_cast<KFileTreeViewItem*>(item);
00266 kdDebug(250) << "hit slotCollapsed" << endl;
00267 if( kftvi && kftvi->isDir())
00268 {
00269 item->setPixmap( 0, itemIcon(kftvi));
00270 }
00271 }
00272
00273 void KFileTreeView::slotExpanded( QListViewItem *item )
00274 {
00275 kdDebug(250) << "slotExpanded here !" << endl;
00276
00277 if( ! item ) return;
00278
00279 KFileTreeViewItem *it = static_cast<KFileTreeViewItem*>(item);
00280 KFileTreeBranch *branch = it->branch();
00281
00282
00283 if( it->isDir() && branch && item->childCount() == 0 )
00284 {
00285
00286 kdDebug(250 ) << "starting to open " << it->url().prettyURL() << endl;
00287 startAnimation( it );
00288 bool branchAnswer = branch->populate( it->url(), it );
00289 kdDebug(250) << "Branches answer: " << branchAnswer << endl;
00290 if( ! branchAnswer )
00291 {
00292 kdDebug(250) << "ERR: Could not populate!" << endl;
00293 stopAnimation( it );
00294 }
00295 }
00296
00297
00298 if( it->isDir() && isOpen( item ) )
00299 {
00300 kdDebug(250)<< "Setting open Pixmap" << endl;
00301 item->setPixmap( 0, itemIcon( it ));
00302 }
00303 }
00304
00305
00306
00307 void KFileTreeView::slotExecuted( QListViewItem *item )
00308 {
00309 if ( !item )
00310 return;
00311
00312
00313
00314 if( static_cast<KFileTreeViewItem*>(item)->isDir())
00315 {
00316 item->setOpen( !item->isOpen() );
00317 }
00318 }
00319
00320
00321 void KFileTreeView::slotAutoOpenFolder()
00322 {
00323 m_autoOpenTimer->stop();
00324
00325 if ( !m_dropItem || m_dropItem->isOpen() )
00326 return;
00327
00328 m_dropItem->setOpen( true );
00329 m_dropItem->repaint();
00330 }
00331
00332
00333 void KFileTreeView::slotSelectionChanged()
00334 {
00335 if ( !m_dropItem )
00336 {
00337 }
00338 }
00339
00340
00341 KFileTreeBranch* KFileTreeView::addBranch( const KURL &path, const QString& name,
00342 bool showHidden )
00343 {
00344 const QPixmap& folderPix = KMimeType::mimeType("inode/directory")->pixmap( KIcon::Small );
00345
00346 return addBranch( path, name, folderPix, showHidden);
00347 }
00348
00349 KFileTreeBranch* KFileTreeView::addBranch( const KURL &path, const QString& name,
00350 const QPixmap& pix, bool showHidden )
00351 {
00352 kdDebug(250) << "adding another root " << path.prettyURL() << endl;
00353
00354
00355 KFileTreeBranch *newBranch = new KFileTreeBranch( this, path, name, pix,
00356 showHidden );
00357 return addBranch(newBranch);
00358 }
00359
00360 KFileTreeBranch *KFileTreeView::addBranch(KFileTreeBranch *newBranch)
00361 {
00362 connect( newBranch, SIGNAL(populateFinished( KFileTreeViewItem* )),
00363 this, SLOT( slotPopulateFinished( KFileTreeViewItem* )));
00364
00365 connect( newBranch, SIGNAL( newTreeViewItems( KFileTreeBranch*,
00366 const KFileTreeViewItemList& )),
00367 this, SLOT( slotNewTreeViewItems( KFileTreeBranch*,
00368 const KFileTreeViewItemList& )));
00369
00370 m_branches.append( newBranch );
00371 return( newBranch );
00372 }
00373
00374 KFileTreeBranch *KFileTreeView::branch( const QString& searchName )
00375 {
00376 KFileTreeBranch *branch = 0;
00377 QPtrListIterator<KFileTreeBranch> it( m_branches );
00378
00379 while ( (branch = it.current()) != 0 ) {
00380 ++it;
00381 QString bname = branch->name();
00382 kdDebug(250) << "This is the branches name: " << bname << endl;
00383 if( bname == searchName )
00384 {
00385 kdDebug(250) << "Found branch " << bname << " and return ptr" << endl;
00386 return( branch );
00387 }
00388 }
00389 return ( 0L );
00390 }
00391
00392 KFileTreeBranchList& KFileTreeView::branches()
00393 {
00394 return( m_branches );
00395 }
00396
00397
00398 bool KFileTreeView::removeBranch( KFileTreeBranch *branch )
00399 {
00400 if(m_branches.contains(branch))
00401 {
00402 delete (branch->root());
00403 m_branches.remove( branch );
00404 return true;
00405 }
00406 else
00407 {
00408 return false;
00409 }
00410 }
00411
00412 void KFileTreeView::setDirOnlyMode( KFileTreeBranch* branch, bool bom )
00413 {
00414 if( branch )
00415 {
00416 branch->setDirOnlyMode( bom );
00417 }
00418 }
00419
00420
00421 void KFileTreeView::slotPopulateFinished( KFileTreeViewItem *it )
00422 {
00423 if( it && it->isDir())
00424 stopAnimation( it );
00425 }
00426
00427 void KFileTreeView::slotNewTreeViewItems( KFileTreeBranch* branch, const KFileTreeViewItemList& itemList )
00428 {
00429 if( ! branch ) return;
00430 kdDebug(250) << "hitting slotNewTreeViewItems" << endl;
00431
00432
00433
00434
00435
00436
00437
00438
00439 if( ! m_nextUrlToSelect.isEmpty() )
00440 {
00441 KFileTreeViewItemListIterator it( itemList );
00442
00443 bool end = false;
00444 for( ; !end && it.current(); ++it )
00445 {
00446 KURL url = (*it)->url();
00447
00448 if( m_nextUrlToSelect.equals(url, true ))
00449 {
00450 setCurrentItem( static_cast<QListViewItem*>(*it) );
00451 m_nextUrlToSelect = KURL();
00452 end = true;
00453 }
00454 }
00455 }
00456 }
00457
00458 QPixmap KFileTreeView::itemIcon( KFileTreeViewItem *item, int gap ) const
00459 {
00460 QPixmap pix;
00461 kdDebug(250) << "Setting icon for column " << gap << endl;
00462
00463 if( item )
00464 {
00465
00466 KFileTreeBranch *brnch = item->branch();
00467 if( item == brnch->root() )
00468 {
00469 pix = brnch->pixmap();
00470 if( m_wantOpenFolderPixmaps && brnch->root()->isOpen() )
00471 {
00472 pix = brnch->openPixmap();
00473 }
00474 }
00475 else
00476 {
00477
00478 pix = item->fileItem()->pixmap( KIcon::SizeSmall );
00479
00480
00481
00482 if( item->isDir() && m_wantOpenFolderPixmaps )
00483 {
00484 if( isOpen( static_cast<QListViewItem*>(item)))
00485 pix = m_openFolderPixmap;
00486 }
00487 }
00488 }
00489
00490 return pix;
00491 }
00492
00493
00494 void KFileTreeView::slotAnimation()
00495 {
00496 MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.begin();
00497 MapCurrentOpeningFolders::Iterator end = m_mapCurrentOpeningFolders.end();
00498 for (; it != end; ++it )
00499 {
00500 uint & iconNumber = it.data().iconNumber;
00501 QString icon = QString::fromLatin1( it.data().iconBaseName ).append( QString::number( iconNumber ) );
00502
00503 it.key()->setPixmap( 0, SmallIcon( icon ));
00504
00505 iconNumber++;
00506 if ( iconNumber > it.data().iconCount )
00507 iconNumber = 1;
00508 }
00509 }
00510
00511
00512 void KFileTreeView::startAnimation( KFileTreeViewItem * item, const char * iconBaseName, uint iconCount )
00513 {
00514
00515 if( ! item )
00516 {
00517 kdDebug(250) << " startAnimation Got called without valid item !" << endl;
00518 return;
00519 }
00520
00521 m_mapCurrentOpeningFolders.insert( item,
00522 AnimationInfo( iconBaseName,
00523 iconCount,
00524 itemIcon(item, 0) ) );
00525 if ( !m_animationTimer->isActive() )
00526 m_animationTimer->start( 50 );
00527 }
00528
00529 void KFileTreeView::stopAnimation( KFileTreeViewItem * item )
00530 {
00531 if( ! item ) return;
00532
00533 kdDebug(250) << "Stoping Animation !" << endl;
00534
00535 MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.find(item);
00536 if ( it != m_mapCurrentOpeningFolders.end() )
00537 {
00538 if( item->isDir() && isOpen( item) )
00539 {
00540 kdDebug(250) << "Setting folder open pixmap !" << endl;
00541 item->setPixmap( 0, itemIcon( item ));
00542 }
00543 else
00544 {
00545 item->setPixmap( 0, it.data().originalPixmap );
00546 }
00547 m_mapCurrentOpeningFolders.remove( item );
00548 }
00549 else
00550 {
00551 if( item )
00552 kdDebug(250)<< "StopAnimation - could not find item " << item->url().prettyURL()<< endl;
00553 else
00554 kdDebug(250)<< "StopAnimation - item is zero !" << endl;
00555 }
00556 if (m_mapCurrentOpeningFolders.isEmpty())
00557 m_animationTimer->stop();
00558 }
00559
00560 KFileTreeViewItem * KFileTreeView::currentKFileTreeViewItem() const
00561 {
00562 return static_cast<KFileTreeViewItem *>( selectedItem() );
00563 }
00564
00565 KURL KFileTreeView::currentURL() const
00566 {
00567 KFileTreeViewItem *item = currentKFileTreeViewItem();
00568 if ( item )
00569 return currentKFileTreeViewItem()->url();
00570 else
00571 return KURL();
00572 }
00573
00574 void KFileTreeView::slotOnItem( QListViewItem *item )
00575 {
00576 KFileTreeViewItem *i = static_cast<KFileTreeViewItem *>( item );
00577 if( i )
00578 {
00579 const KURL url = i->url();
00580 if ( url.isLocalFile() )
00581 emit onItem( url.path() );
00582 else
00583 emit onItem( url.prettyURL() );
00584 }
00585 }
00586
00587 void KFileTreeView::slotItemRenamed(QListViewItem* item, const QString &name, int col)
00588 {
00589 (void) item;
00590 kdDebug(250) << "Do not bother: " << name << col << endl;
00591 }
00592
00593 KFileTreeViewItem *KFileTreeView::findItem( const QString& branchName, const QString& relUrl )
00594 {
00595 KFileTreeBranch *br = branch( branchName );
00596 return( findItem( br, relUrl ));
00597 }
00598
00599 KFileTreeViewItem *KFileTreeView::findItem( KFileTreeBranch* brnch, const QString& relUrl )
00600 {
00601 KFileTreeViewItem *ret = 0;
00602 if( brnch )
00603 {
00604 KURL url = brnch->rootUrl();
00605
00606 if( ! relUrl.isEmpty() && relUrl != QString::fromLatin1("/") )
00607 {
00608 QString partUrl( relUrl );
00609
00610 if( partUrl.endsWith("/"))
00611 partUrl.truncate( relUrl.length()-1 );
00612
00613 url.addPath( partUrl );
00614
00615 kdDebug(250) << "assembled complete dir string " << url.prettyURL() << endl;
00616
00617 KFileItem *fi = brnch->findByURL( url );
00618 if( fi )
00619 {
00620 ret = static_cast<KFileTreeViewItem*>( fi->extraData( brnch ));
00621 kdDebug(250) << "Found item !" <<ret << endl;
00622 }
00623 }
00624 else
00625 {
00626 ret = brnch->root();
00627 }
00628 }
00629 return( ret );
00630 }
00631
00634
00635
00636 void KFileTreeViewToolTip::maybeTip( const QPoint & )
00637 {
00638 #if 0
00639 QListViewItem *item = m_view->itemAt( point );
00640 if ( item ) {
00641 QString text = static_cast<KFileViewItem*>( item )->toolTipText();
00642 if ( !text.isEmpty() )
00643 tip ( m_view->itemRect( item ), text );
00644 }
00645 #endif
00646 }
00647
00648 void KFileTreeView::virtual_hook( int id, void* data )
00649 { KListView::virtual_hook( id, data ); }
00650
00651 #include "kfiletreeview.moc"