kio Library API Documentation

kfiletreeview.cpp

00001 /* This file is part of the KDEproject 00002 Copyright (C) 2000 David Faure <faure@kde.org> 00003 2000 Carsten Pfeiffer <pfeiffer@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 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 /* The executed-Slot only opens a path, while the expanded-Slot populates it */ 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 /* connections from the konqtree widget */ 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 // we must make sure that the KFileTreeViewItems are deleted _before_ the 00087 // branches are deleted. Otherwise, the KFileItems would be destroyed 00088 // and the KFileTreeViewItems had dangling pointers to them. 00089 hide(); 00090 clear(); 00091 m_branches.clear(); // finally delete the branches and KFileItems 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 // "afterme" is 0 when aiming at a directory itself 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 // Restore the current item to what it was before the dragging (#17070) 00154 if ( m_currentBeforeDropItem ) 00155 { 00156 setSelected( m_currentBeforeDropItem, true ); 00157 ensureItemVisible( m_currentBeforeDropItem ); 00158 } 00159 else 00160 setSelected( m_dropItem, false ); // no item selected 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 //kdDebug(250) << " parent=" << (parent?parent->text(0):QString::null) 00184 // << " afterme=" << (afterme?afterme->text(0):QString::null) << endl; 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 // can happen when dropping above the root item 00204 // Should we choose the first branch in such a case ?? 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 // kdDebug(250) << "Do accept drops: " << ancestOK << endl; 00217 ancestOK = ancestOK && itemsMovable(); 00218 // kdDebug(250) << "acceptDrag: " << ancestOK << endl; 00219 // kdDebug(250) << "canDecode: " << KURLDrag::canDecode(e) << endl; 00220 // kdDebug(250) << "action: " << e->action() << endl; 00221 00222 /* KListView::acceptDrag(e); */ 00223 /* this is what KListView does: 00224 * acceptDrops() && itemsMovable() && (e->source()==viewport()); 00225 * ask acceptDrops and itemsMovable, but not the third 00226 */ 00227 return ancestOK && KURLDrag::canDecode( e ) && 00228 // Why this test? All DnDs are one of those AFAIK (DF) 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 /* Start the animation for the branch object */ 00283 if( it->isDir() && branch && item->childCount() == 0 ) 00284 { 00285 /* check here if the branch really needs to be populated again */ 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 /* set a pixmap 'open folder' */ 00298 if( it->isDir() && isOpen( item ) ) 00299 { 00300 kdDebug(250)<< "Setting open Pixmap" << endl; 00301 item->setPixmap( 0, itemIcon( it )); // 0, m_openFolderPixmap ); 00302 } 00303 } 00304 00305 00306 00307 void KFileTreeView::slotExecuted( QListViewItem *item ) 00308 { 00309 if ( !item ) 00310 return; 00311 /* This opens the dir and causes the Expanded-slot to be called, 00312 * which strolls through the children. 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 ) // don't do this while the dragmove thing 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 /* Open a new branch */ 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 /* Sometimes it happens that new items should become selected, i.e. if the user 00433 * creates a new dir, he probably wants it to be selected. This can not be done 00434 * right after creating the directory or file, because it takes some time until 00435 * the item appears here in the treeview. Thus, the creation code sets the member 00436 * m_neUrlToSelect to the required url. If this url appears here, the item becomes 00437 * selected and the member nextUrlToSelect will be cleared. 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 )) // ignore trailing / on dirs 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 /* Check if it is a branch root */ 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 // TODO: different modes, user Pixmaps ? 00478 pix = item->fileItem()->pixmap( KIcon::SizeSmall ); // , KIcon::DefaultState); 00479 00480 /* Only if it is a dir and the user wants open dir pixmap and it is open, 00481 * change the fileitem's pixmap to the open folder pixmap. */ 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 // kdDebug(250) << "Loading icon " << icon << endl; 00503 it.key()->setPixmap( 0, SmallIcon( icon )); // KFileTreeViewFactory::instance() ) ); 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 /* TODO: allow specific icons */ 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"
KDE Logo
This file is part of the documentation for kio Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:49:14 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003