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