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