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