kio Library API Documentation

kfiletreebranch.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 2002 Klaas Freitag <freitag@suse.de> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 00021 #include <qfile.h> 00022 00023 #include <kfileitem.h> 00024 #include <kdebug.h> 00025 00026 #include <sys/types.h> 00027 #include <sys/stat.h> 00028 #include <unistd.h> 00029 00030 #include "kfiletreeviewitem.h" 00031 #include "kfiletreebranch.h" 00032 00033 00034 /* --- KFileTreeViewToplevelItem --- */ 00035 KFileTreeBranch::KFileTreeBranch( KFileTreeView *parent, const KURL& url, 00036 const QString& name, 00037 const QPixmap& pix, bool showHidden, 00038 KFileTreeViewItem *branchRoot ) 00039 00040 : KDirLister( false ), 00041 m_root( branchRoot ), 00042 m_startURL( url ), 00043 m_name ( name ), 00044 m_rootIcon( pix ), 00045 m_openRootIcon( pix ), 00046 m_recurseChildren(true), 00047 m_showExtensions(true) 00048 { 00049 kdDebug( 250) << "Creating branch for url " << url.prettyURL() << endl; 00050 00051 /* if non exists, create one */ 00052 if( ! branchRoot ) 00053 { 00054 m_root = new KFileTreeViewItem( parent, 00055 new KFileItem( url, "inode/directory", 00056 S_IFDIR ), 00057 this ); 00058 } 00059 00060 m_root->setExpandable( true ); 00061 m_root->setPixmap( 0, pix ); 00062 m_root->setText( 0, name ); 00063 00064 setShowingDotFiles( showHidden ); 00065 00066 connect( this, SIGNAL( refreshItems(const KFileItemList&)), 00067 this, SLOT ( slotRefreshItems( const KFileItemList& ))); 00068 00069 connect( this, SIGNAL( newItems(const KFileItemList&)), 00070 this, SLOT ( addItems( const KFileItemList& ))); 00071 00072 connect( this, SIGNAL( completed(const KURL& )), 00073 this, SLOT(slCompleted(const KURL&))); 00074 00075 connect( this, SIGNAL( started( const KURL& )), 00076 this, SLOT( slotListerStarted( const KURL& ))); 00077 00078 connect( this, SIGNAL( deleteItem( KFileItem* )), 00079 this, SLOT( slotDeleteItem( KFileItem* ))); 00080 00081 connect( this, SIGNAL( canceled(const KURL&) ), 00082 this, SLOT( slotCanceled(const KURL&) )); 00083 00084 connect( this, SIGNAL( clear()), 00085 this, SLOT( slotDirlisterClear())); 00086 00087 connect( this, SIGNAL( clear(const KURL&)), 00088 this, SLOT( slotDirlisterClearURL(const KURL&))); 00089 00090 connect( this, SIGNAL( redirection( const KURL& , const KURL& ) ), 00091 this, SLOT( slotRedirect( const KURL&, const KURL& ))); 00092 00093 m_openChildrenURLs.append( url ); 00094 } 00095 00096 void KFileTreeBranch::setOpenPixmap( const QPixmap& pix ) 00097 { 00098 m_openRootIcon = pix; 00099 00100 if( root()->isOpen()) 00101 { 00102 root()->setPixmap( 0, pix ); 00103 } 00104 } 00105 00106 void KFileTreeBranch::slotListerStarted( const KURL &url ) 00107 { 00108 /* set the parent correct if it is zero. */ 00109 kdDebug( 250) << "Starting to list " << url.prettyURL() << endl; 00110 } 00111 00112 00113 KFileTreeViewItem *KFileTreeBranch::parentKFTVItem( KFileItem *item ) 00114 { 00115 KFileTreeViewItem *parent = 0; 00116 00117 if( ! item ) return 0; 00118 00119 /* If it is a directory, check, if it exists in the dict. If not, go one up 00120 * and check again. 00121 */ 00122 KURL url = item->url(); 00123 // kdDebug(250) << "Item's url is " << url.prettyURL() << endl; 00124 KURL dirUrl( url ); 00125 dirUrl.setFileName( QString::null ); 00126 // kdDebug(250) << "Directory url is " << dirUrl.prettyURL() << endl; 00127 00128 parent = findTVIByURL( dirUrl ); 00129 // kdDebug(250) << "Returning as parent item <" << parent << ">" << endl; 00130 return( parent ); 00131 } 00132 00133 00134 void KFileTreeBranch::slotRefreshItems( const KFileItemList& list ) 00135 { 00136 KFileItemListIterator it( list ); 00137 kdDebug(250) << "Refreshing " << list.count() << " items !" << endl; 00138 KFileItem *currItem; 00139 KFileTreeViewItem *item = 0; 00140 00141 while ( (currItem = it.current()) != 0 ) 00142 { 00143 item = findTVIByURL(currItem->url()); 00144 if (item) { 00145 item->setPixmap(0, item->fileItem()->pixmap( KIcon::SizeSmall )); 00146 item->setText( 0, item->fileItem()->text()); 00147 } 00148 ++it; 00149 } 00150 } 00151 00152 void KFileTreeBranch::addItems( const KFileItemList& list ) 00153 { 00154 KFileItemListIterator it( list ); 00155 kdDebug(250) << "Adding " << list.count() << " items !" << endl; 00156 KFileItem *currItem; 00157 KFileTreeViewItemList treeViewItList; 00158 KFileTreeViewItem *parentItem = 0; 00159 00160 while ( (currItem = it.current()) != 0 ) 00161 { 00162 parentItem = parentKFTVItem( currItem ); 00163 00164 00165 /* Only create a new KFileTreeViewItem if it does not yet exist */ 00166 KFileTreeViewItem *newKFTVI = 00167 static_cast<KFileTreeViewItem *>(currItem->extraData( this )); 00168 00169 if( ! newKFTVI ) 00170 { 00171 newKFTVI = createTreeViewItem( parentItem, currItem ); 00172 if (!newKFTVI) 00173 { 00174 // TODO: Don't fail if parentItem == 0 00175 ++it; 00176 continue; 00177 } 00178 currItem->setExtraData( this, newKFTVI ); 00179 00180 /* Cut off the file extension in case it is not a directory */ 00181 if( !m_showExtensions && !currItem->isDir() ) /* Need to cut the extension */ 00182 { 00183 QString name = currItem->text(); 00184 int mPoint = name.findRev( '.' ); 00185 if( mPoint > 0 ) 00186 name = name.left( mPoint ); 00187 newKFTVI->setText( 0, name ); 00188 } 00189 } 00190 00191 /* Now try to find out if there are children for dirs in the treeview */ 00192 /* This stats a directory on the local file system and checks the */ 00193 /* hardlink entry in the stat-buf. This works only for local directories. */ 00194 if( dirOnlyMode() && !m_recurseChildren && currItem->isLocalFile( ) && currItem->isDir() ) 00195 { 00196 KURL url = currItem->url(); 00197 QString filename = url.directory( false, true ) + url.fileName(); 00198 /* do the stat trick of Carsten. The problem is, that the hardlink 00199 * count only contains directory links. Thus, this method only seem 00200 * to work in dir-only mode */ 00201 kdDebug(250) << "Doing stat on " << filename << endl; 00202 struct stat statBuf; 00203 if( stat( QFile::encodeName( filename ), &statBuf ) == 0 ) 00204 { 00205 int hardLinks = statBuf.st_nlink; /* Count of dirs */ 00206 kdDebug(250) << "stat succeeded, hardlinks: " << hardLinks << endl; 00207 // If the link count is > 2, the directory likely has subdirs. If it's < 2 00208 // it's something weird like a mounted SMB share. In that case we don't know 00209 // if there are subdirs, thus show it as expandable. 00210 00211 if( hardLinks != 2 ) 00212 { 00213 newKFTVI->setExpandable(true); 00214 } 00215 else 00216 { 00217 newKFTVI->setExpandable(false); 00218 } 00219 if( hardLinks >= 2 ) // "Normal" directory with subdirs 00220 { 00221 kdDebug(250) << "Emitting for " << url.prettyURL() << endl; 00222 emit( directoryChildCount( newKFTVI, hardLinks-2)); // parentItem, hardLinks-1 )); 00223 } 00224 } 00225 else 00226 { 00227 kdDebug(250) << "stat of " << filename << " failed !" << endl; 00228 } 00229 } 00230 ++it; 00231 00232 treeViewItList.append( newKFTVI ); 00233 } 00234 00235 emit newTreeViewItems( this, treeViewItList ); 00236 } 00237 00238 KFileTreeViewItem* KFileTreeBranch::createTreeViewItem( KFileTreeViewItem *parent, 00239 KFileItem *fileItem ) 00240 { 00241 KFileTreeViewItem *tvi = 0; 00242 if( parent && fileItem ) 00243 { 00244 tvi = new KFileTreeViewItem( parent, 00245 fileItem, 00246 this ); 00247 } 00248 else 00249 { 00250 kdDebug(250) << "createTreeViewItem: Have no parent" << endl; 00251 } 00252 return( tvi ); 00253 } 00254 00255 void KFileTreeBranch::setChildRecurse( bool t ) 00256 { 00257 m_recurseChildren = t; 00258 if( t == false ) 00259 m_openChildrenURLs.clear(); 00260 } 00261 00262 00263 void KFileTreeBranch::setShowExtensions( bool visible ) 00264 { 00265 m_showExtensions = visible; 00266 } 00267 00268 bool KFileTreeBranch::showExtensions( ) const 00269 { 00270 return( m_showExtensions ); 00271 } 00272 00273 /* 00274 * The signal that tells that a directory was deleted may arrive before the signal 00275 * for its children arrive. Thus, we must walk through the children of a dir and 00276 * remove them before removing the dir itself. 00277 */ 00278 void KFileTreeBranch::slotDeleteItem( KFileItem *it ) 00279 { 00280 if( !it ) return; 00281 kdDebug(250) << "Slot Delete Item hitted for " << it->url().prettyURL() << endl; 00282 00283 KFileTreeViewItem *kfti = static_cast<KFileTreeViewItem*>(it->extraData(this)); 00284 00285 if( kfti ) 00286 { 00287 kdDebug( 250 ) << "Child count: " << kfti->childCount() << endl; 00288 if( kfti->childCount() > 0 ) 00289 { 00290 KFileTreeViewItem *child = static_cast<KFileTreeViewItem*>(kfti->firstChild()); 00291 00292 while( child ) 00293 { 00294 kdDebug(250) << "Calling child to be deleted !" << endl; 00295 KFileTreeViewItem *nextChild = static_cast<KFileTreeViewItem*>(child->nextSibling()); 00296 slotDeleteItem( child->fileItem()); 00297 child = nextChild; 00298 } 00299 } 00300 00301 kdDebug(250) << "Found corresponding KFileTreeViewItem" << endl; 00302 delete( kfti ); 00303 } 00304 else 00305 { 00306 kdDebug(250) << "Error: kfiletreeviewitem: "<< kfti << endl; 00307 } 00308 } 00309 00310 00311 void KFileTreeBranch::slotCanceled( const KURL& url ) 00312 { 00313 // ### anything else to do? 00314 // remove the url from the childrento-recurse-list 00315 m_openChildrenURLs.remove( url); 00316 00317 // stop animations etc. 00318 KFileTreeViewItem *item = findTVIByURL(url); 00319 if (!item) return; // Uh oh... 00320 emit populateFinished(item); 00321 } 00322 00323 void KFileTreeBranch::slotDirlisterClear() 00324 { 00325 kdDebug(250)<< "*** Clear all !" << endl; 00326 /* this slots needs to clear all listed items, but NOT the root item */ 00327 if( m_root ) 00328 deleteChildrenOf( m_root ); 00329 } 00330 00331 void KFileTreeBranch::slotDirlisterClearURL( const KURL& url ) 00332 { 00333 kdDebug(250)<< "*** Clear for URL !" << url.prettyURL() << endl; 00334 KFileItem *item = findByURL( url ); 00335 if( item ) 00336 { 00337 KFileTreeViewItem *ftvi = 00338 static_cast<KFileTreeViewItem *>(item->extraData( this )); 00339 deleteChildrenOf( ftvi ); 00340 } 00341 } 00342 00343 void KFileTreeBranch::deleteChildrenOf( QListViewItem *parent ) 00344 { 00345 // for some strange reason, slotDirlisterClearURL() sometimes calls us 00346 // with a 0L parent. 00347 if ( !parent ) 00348 return; 00349 00350 while ( parent->firstChild() ) 00351 delete parent->firstChild(); 00352 } 00353 00354 void KFileTreeBranch::slotRedirect( const KURL& oldUrl, const KURL&newUrl ) 00355 { 00356 if( oldUrl.equals( m_startURL, true )) 00357 { 00358 m_startURL = newUrl; 00359 } 00360 } 00361 00362 KFileTreeViewItem* KFileTreeBranch::findTVIByURL( const KURL& url ) 00363 { 00364 KFileTreeViewItem *resultItem = 0; 00365 00366 if( m_startURL.equals(url, true) ) 00367 { 00368 kdDebug(250) << "findByURL: Returning root as a parent !" << endl; 00369 resultItem = m_root; 00370 } 00371 else if( m_lastFoundURL.equals( url, true )) 00372 { 00373 kdDebug(250) << "findByURL: Returning from lastFoundURL!" << endl; 00374 resultItem = m_lastFoundItem; 00375 } 00376 else 00377 { 00378 kdDebug(250) << "findByURL: searching by dirlister: " << url.url() << endl; 00379 00380 KFileItem *it = findByURL( url ); 00381 00382 if( it ) 00383 { 00384 resultItem = static_cast<KFileTreeViewItem*>(it->extraData(this)); 00385 m_lastFoundItem = resultItem; 00386 m_lastFoundURL = url; 00387 } 00388 } 00389 00390 return( resultItem ); 00391 } 00392 00393 00394 void KFileTreeBranch::slCompleted( const KURL& url ) 00395 { 00396 kdDebug(250) << "SlotCompleted hit for " << url.prettyURL() << endl; 00397 KFileTreeViewItem *currParent = findTVIByURL( url ); 00398 if( ! currParent ) return; 00399 00400 kdDebug(250) << "current parent " << currParent << " is already listed: " 00401 << currParent->alreadyListed() << endl; 00402 00403 emit( populateFinished(currParent)); 00404 emit( directoryChildCount(currParent, currParent->childCount())); 00405 00406 /* This is a walk through the children of the last populated directory. 00407 * Here we start the dirlister on every child of the dir and wait for its 00408 * finish. When it has finished, we go to the next child. 00409 * This must be done for non local file systems in dirOnly- and Full-Mode 00410 * and for local file systems only in full mode, because the stat trick 00411 * (see addItem-Method) does only work for dirs, not for files in the directory. 00412 */ 00413 /* Set bit that the parent dir was listed completely */ 00414 currParent->setListed(true); 00415 00416 kdDebug(250) << "recurseChildren: " << m_recurseChildren << endl; 00417 kdDebug(250) << "isLocalFile: " << m_startURL.isLocalFile() << endl; 00418 kdDebug(250) << "dirOnlyMode: " << dirOnlyMode() << endl; 00419 00420 00421 if( m_recurseChildren && (!m_startURL.isLocalFile() || ! dirOnlyMode()) ) 00422 { 00423 bool wantRecurseUrl = false; 00424 /* look if the url is in the list for url to recurse */ 00425 for ( KURL::List::Iterator it = m_openChildrenURLs.begin(); 00426 it != m_openChildrenURLs.end(); ++it ) 00427 { 00428 /* it is only interesting that the url _is_in_ the list. */ 00429 if( (*it).equals( url, true ) ) 00430 wantRecurseUrl = true; 00431 } 00432 00433 KFileTreeViewItem *nextChild = 0; 00434 kdDebug(250) << "Recursing " << url.prettyURL() << "? " << wantRecurseUrl << endl; 00435 00436 if( wantRecurseUrl && currParent ) 00437 { 00438 00439 /* now walk again through the tree and populate the children to get +-signs */ 00440 /* This is the starting point. The visible folder has finished, 00441 processing the children has not yet started */ 00442 nextChild = static_cast<KFileTreeViewItem*> 00443 (static_cast<QListViewItem*>(currParent)->firstChild()); 00444 00445 if( ! nextChild ) 00446 { 00447 /* This happens if there is no child at all */ 00448 kdDebug( 250 ) << "No children to recuse" << endl; 00449 } 00450 00451 /* Since we have listed the children to recurse, we can remove the entry 00452 * in the list of the URLs to see the children. 00453 */ 00454 m_openChildrenURLs.remove(url); 00455 } 00456 00457 if( nextChild ) /* This implies that idx > -1 */ 00458 { 00459 /* Next child is defined. We start a dirlister job on every child item 00460 * which is a directory to find out how much children are in the child 00461 * of the last opened dir 00462 */ 00463 00464 /* Skip non directory entries */ 00465 while( nextChild ) 00466 { 00467 if( nextChild->isDir() && ! nextChild->alreadyListed()) 00468 { 00469 KFileItem *kfi = nextChild->fileItem(); 00470 if( kfi && kfi->isReadable()) 00471 { 00472 KURL recurseUrl = kfi->url(); 00473 kdDebug(250) << "Starting to recurse NOW " << recurseUrl.prettyURL() << endl; 00474 openURL( recurseUrl, true ); 00475 } 00476 } 00477 nextChild = static_cast<KFileTreeViewItem*>(static_cast<QListViewItem*>(nextChild->nextSibling())); 00478 // kdDebug(250) << "Next child " << m_nextChild << endl; 00479 } 00480 } 00481 } 00482 else 00483 { 00484 kdDebug(250) << "skipping to recurse in complete-slot" << endl; 00485 } 00486 } 00487 00488 /* This slot is called when a treeviewitem is expanded in the gui */ 00489 bool KFileTreeBranch::populate( const KURL& url, KFileTreeViewItem *currItem ) 00490 { 00491 bool ret = false; 00492 if( ! currItem ) 00493 return ret; 00494 00495 kdDebug(250) << "Populating <" << url.prettyURL() << ">" << endl; 00496 00497 /* Add this url to the list of urls to recurse for children */ 00498 if( m_recurseChildren ) 00499 { 00500 m_openChildrenURLs.append( url ); 00501 kdDebug(250) << "Appending to list " << url.prettyURL() << endl; 00502 } 00503 00504 if( ! currItem->alreadyListed() ) 00505 { 00506 /* start the lister */ 00507 ret = openURL( url, true ); 00508 } 00509 else 00510 { 00511 kdDebug(250) << "Children already existing in treeview!" << endl; 00512 slCompleted( url ); 00513 ret = true; 00514 } 00515 return ret; 00516 } 00517 00518 void KFileTreeBranch::virtual_hook( int id, void* data ) 00519 { KDirLister::virtual_hook( id, data ); } 00520 00521 #include "kfiletreebranch.moc" 00522
KDE Logo
This file is part of the documentation for kio Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:29:26 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003