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