00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qfile.h>
00022
00023 #include <kfileitem.h>
00024 #include <kdebug.h>
00025 #include <kde_file.h>
00026
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <unistd.h>
00030
00031 #include "kfiletreeviewitem.h"
00032 #include "kfiletreebranch.h"
00033
00034
00035
00036 KFileTreeBranch::KFileTreeBranch( KFileTreeView *parent, const KURL& url,
00037 const QString& name,
00038 const QPixmap& pix, bool showHidden,
00039 KFileTreeViewItem *branchRoot )
00040
00041 : KDirLister( false ),
00042 m_root( branchRoot ),
00043 m_startURL( url ),
00044 m_name ( name ),
00045 m_rootIcon( pix ),
00046 m_openRootIcon( pix ),
00047 m_recurseChildren(true),
00048 m_showExtensions(true)
00049 {
00050 kdDebug( 250) << "Creating branch for url " << url.prettyURL() << endl;
00051
00052
00053 if( ! branchRoot )
00054 {
00055 m_root = new KFileTreeViewItem( parent,
00056 new KFileItem( url, "inode/directory",
00057 S_IFDIR ),
00058 this );
00059 }
00060
00061 m_root->setExpandable( true );
00062 m_root->setPixmap( 0, pix );
00063 m_root->setText( 0, name );
00064
00065 setShowingDotFiles( showHidden );
00066
00067 connect( this, SIGNAL( refreshItems(const KFileItemList&)),
00068 this, SLOT ( slotRefreshItems( const KFileItemList& )));
00069
00070 connect( this, SIGNAL( newItems(const KFileItemList&)),
00071 this, SLOT ( addItems( const KFileItemList& )));
00072
00073 connect( this, SIGNAL( completed(const KURL& )),
00074 this, SLOT(slCompleted(const KURL&)));
00075
00076 connect( this, SIGNAL( started( const KURL& )),
00077 this, SLOT( slotListerStarted( const KURL& )));
00078
00079 connect( this, SIGNAL( deleteItem( KFileItem* )),
00080 this, SLOT( slotDeleteItem( KFileItem* )));
00081
00082 connect( this, SIGNAL( canceled(const KURL&) ),
00083 this, SLOT( slotCanceled(const KURL&) ));
00084
00085 connect( this, SIGNAL( clear()),
00086 this, SLOT( slotDirlisterClear()));
00087
00088 connect( this, SIGNAL( clear(const KURL&)),
00089 this, SLOT( slotDirlisterClearURL(const KURL&)));
00090
00091 connect( this, SIGNAL( redirection( const KURL& , const KURL& ) ),
00092 this, SLOT( slotRedirect( const KURL&, const KURL& )));
00093
00094 m_openChildrenURLs.append( url );
00095 }
00096
00097 void KFileTreeBranch::setOpenPixmap( const QPixmap& pix )
00098 {
00099 m_openRootIcon = pix;
00100
00101 if( root()->isOpen())
00102 {
00103 root()->setPixmap( 0, pix );
00104 }
00105 }
00106
00107 void KFileTreeBranch::slotListerStarted( const KURL &url )
00108 {
00109
00110 kdDebug( 250) << "Starting to list " << url.prettyURL() << endl;
00111 }
00112
00113
00114 KFileTreeViewItem *KFileTreeBranch::parentKFTVItem( KFileItem *item )
00115 {
00116 KFileTreeViewItem *parent = 0;
00117
00118 if( ! item ) return 0;
00119
00120
00121
00122
00123 KURL url = item->url();
00124
00125 KURL dirUrl( url );
00126 dirUrl.setFileName( QString::null );
00127
00128
00129 parent = findTVIByURL( dirUrl );
00130
00131 return( parent );
00132 }
00133
00134
00135 void KFileTreeBranch::slotRefreshItems( const KFileItemList& list )
00136 {
00137 KFileItemListIterator it( list );
00138 kdDebug(250) << "Refreshing " << list.count() << " items !" << endl;
00139 KFileItem *currItem;
00140 KFileTreeViewItem *item = 0;
00141
00142 while ( (currItem = it.current()) != 0 )
00143 {
00144 item = findTVIByURL(currItem->url());
00145 if (item) {
00146 item->setPixmap(0, item->fileItem()->pixmap( KIcon::SizeSmall ));
00147 item->setText( 0, item->fileItem()->text());
00148 }
00149 ++it;
00150 }
00151 }
00152
00153 void KFileTreeBranch::addItems( const KFileItemList& list )
00154 {
00155 KFileItemListIterator it( list );
00156 kdDebug(250) << "Adding " << list.count() << " items !" << endl;
00157 KFileItem *currItem;
00158 KFileTreeViewItemList treeViewItList;
00159 KFileTreeViewItem *parentItem = 0;
00160
00161 while ( (currItem = it.current()) != 0 )
00162 {
00163 parentItem = parentKFTVItem( currItem );
00164
00165
00166
00167 KFileTreeViewItem *newKFTVI =
00168 static_cast<KFileTreeViewItem *>(currItem->extraData( this ));
00169
00170 if( ! newKFTVI )
00171 {
00172 newKFTVI = createTreeViewItem( parentItem, currItem );
00173 if (!newKFTVI)
00174 {
00175
00176 ++it;
00177 continue;
00178 }
00179 currItem->setExtraData( this, newKFTVI );
00180
00181
00182 if( !m_showExtensions && !currItem->isDir() )
00183 {
00184 QString name = currItem->text();
00185 int mPoint = name.findRev( '.' );
00186 if( mPoint > 0 )
00187 name = name.left( mPoint );
00188 newKFTVI->setText( 0, name );
00189 }
00190 }
00191
00192
00193
00194
00195 if( dirOnlyMode() && !m_recurseChildren && currItem->isLocalFile( ) && currItem->isDir() )
00196 {
00197 KURL url = currItem->url();
00198 QString filename = url.directory( false, true ) + url.fileName();
00199
00200
00201
00202 kdDebug(250) << "Doing stat on " << filename << endl;
00203 KDE_struct_stat statBuf;
00204 if( KDE_stat( QFile::encodeName( filename ), &statBuf ) == 0 )
00205 {
00206 int hardLinks = statBuf.st_nlink;
00207 kdDebug(250) << "stat succeeded, hardlinks: " << hardLinks << endl;
00208
00209
00210
00211
00212 if( hardLinks != 2 )
00213 {
00214 newKFTVI->setExpandable(true);
00215 }
00216 else
00217 {
00218 newKFTVI->setExpandable(false);
00219 }
00220 if( hardLinks >= 2 )
00221 {
00222 kdDebug(250) << "Emitting for " << url.prettyURL() << endl;
00223 emit( directoryChildCount( newKFTVI, hardLinks-2));
00224 }
00225 }
00226 else
00227 {
00228 kdDebug(250) << "stat of " << filename << " failed !" << endl;
00229 }
00230 }
00231 ++it;
00232
00233 treeViewItList.append( newKFTVI );
00234 }
00235
00236 emit newTreeViewItems( this, treeViewItList );
00237 }
00238
00239 KFileTreeViewItem* KFileTreeBranch::createTreeViewItem( KFileTreeViewItem *parent,
00240 KFileItem *fileItem )
00241 {
00242 KFileTreeViewItem *tvi = 0;
00243 if( parent && fileItem )
00244 {
00245 tvi = new KFileTreeViewItem( parent,
00246 fileItem,
00247 this );
00248 }
00249 else
00250 {
00251 kdDebug(250) << "createTreeViewItem: Have no parent" << endl;
00252 }
00253 return( tvi );
00254 }
00255
00256 void KFileTreeBranch::setChildRecurse( bool t )
00257 {
00258 m_recurseChildren = t;
00259 if( t == false )
00260 m_openChildrenURLs.clear();
00261 }
00262
00263
00264 void KFileTreeBranch::setShowExtensions( bool visible )
00265 {
00266 m_showExtensions = visible;
00267 }
00268
00269 bool KFileTreeBranch::showExtensions( ) const
00270 {
00271 return( m_showExtensions );
00272 }
00273
00274
00275
00276
00277
00278
00279 void KFileTreeBranch::slotDeleteItem( KFileItem *it )
00280 {
00281 if( !it ) return;
00282 kdDebug(250) << "Slot Delete Item hitted for " << it->url().prettyURL() << endl;
00283
00284 KFileTreeViewItem *kfti = static_cast<KFileTreeViewItem*>(it->extraData(this));
00285
00286 if( kfti )
00287 {
00288 kdDebug( 250 ) << "Child count: " << kfti->childCount() << endl;
00289 if( kfti->childCount() > 0 )
00290 {
00291 KFileTreeViewItem *child = static_cast<KFileTreeViewItem*>(kfti->firstChild());
00292
00293 while( child )
00294 {
00295 kdDebug(250) << "Calling child to be deleted !" << endl;
00296 KFileTreeViewItem *nextChild = static_cast<KFileTreeViewItem*>(child->nextSibling());
00297 slotDeleteItem( child->fileItem());
00298 child = nextChild;
00299 }
00300 }
00301
00302 kdDebug(250) << "Found corresponding KFileTreeViewItem" << endl;
00303 if( m_lastFoundURL.equals(it->url(), true ))
00304 {
00305 m_lastFoundURL = KURL();
00306 m_lastFoundItem = 0L;
00307 }
00308 delete( kfti );
00309 }
00310 else
00311 {
00312 kdDebug(250) << "Error: kfiletreeviewitem: "<< kfti << endl;
00313 }
00314 }
00315
00316
00317 void KFileTreeBranch::slotCanceled( const KURL& url )
00318 {
00319
00320
00321 m_openChildrenURLs.remove( url);
00322
00323
00324 KFileTreeViewItem *item = findTVIByURL(url);
00325 if (!item) return;
00326 emit populateFinished(item);
00327 }
00328
00329 void KFileTreeBranch::slotDirlisterClear()
00330 {
00331 kdDebug(250)<< "*** Clear all !" << endl;
00332
00333 if( m_root )
00334 deleteChildrenOf( m_root );
00335 }
00336
00337 void KFileTreeBranch::slotDirlisterClearURL( const KURL& url )
00338 {
00339 kdDebug(250)<< "*** Clear for URL !" << url.prettyURL() << endl;
00340 KFileItem *item = findByURL( url );
00341 if( item )
00342 {
00343 KFileTreeViewItem *ftvi =
00344 static_cast<KFileTreeViewItem *>(item->extraData( this ));
00345 deleteChildrenOf( ftvi );
00346 }
00347 }
00348
00349 void KFileTreeBranch::deleteChildrenOf( QListViewItem *parent )
00350 {
00351
00352
00353 if ( !parent )
00354 return;
00355
00356 while ( parent->firstChild() )
00357 delete parent->firstChild();
00358 }
00359
00360 void KFileTreeBranch::slotRedirect( const KURL& oldUrl, const KURL&newUrl )
00361 {
00362 if( oldUrl.equals( m_startURL, true ))
00363 {
00364 m_startURL = newUrl;
00365 }
00366 }
00367
00368 KFileTreeViewItem* KFileTreeBranch::findTVIByURL( const KURL& url )
00369 {
00370 KFileTreeViewItem *resultItem = 0;
00371
00372 if( m_startURL.equals(url, true) )
00373 {
00374 kdDebug(250) << "findByURL: Returning root as a parent !" << endl;
00375 resultItem = m_root;
00376 }
00377 else if( m_lastFoundURL.equals( url, true ))
00378 {
00379 kdDebug(250) << "findByURL: Returning from lastFoundURL!" << endl;
00380 resultItem = m_lastFoundItem;
00381 }
00382 else
00383 {
00384 kdDebug(250) << "findByURL: searching by dirlister: " << url.url() << endl;
00385
00386 KFileItem *it = findByURL( url );
00387
00388 if( it )
00389 {
00390 resultItem = static_cast<KFileTreeViewItem*>(it->extraData(this));
00391 m_lastFoundItem = resultItem;
00392 m_lastFoundURL = url;
00393 }
00394 }
00395
00396 return( resultItem );
00397 }
00398
00399
00400 void KFileTreeBranch::slCompleted( const KURL& url )
00401 {
00402 kdDebug(250) << "SlotCompleted hit for " << url.prettyURL() << endl;
00403 KFileTreeViewItem *currParent = findTVIByURL( url );
00404 if( ! currParent ) return;
00405
00406 kdDebug(250) << "current parent " << currParent << " is already listed: "
00407 << currParent->alreadyListed() << endl;
00408
00409 emit( populateFinished(currParent));
00410 emit( directoryChildCount(currParent, currParent->childCount()));
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420 currParent->setListed(true);
00421
00422 kdDebug(250) << "recurseChildren: " << m_recurseChildren << endl;
00423 kdDebug(250) << "isLocalFile: " << m_startURL.isLocalFile() << endl;
00424 kdDebug(250) << "dirOnlyMode: " << dirOnlyMode() << endl;
00425
00426
00427 if( m_recurseChildren && (!m_startURL.isLocalFile() || ! dirOnlyMode()) )
00428 {
00429 bool wantRecurseUrl = false;
00430
00431 for ( KURL::List::Iterator it = m_openChildrenURLs.begin();
00432 it != m_openChildrenURLs.end(); ++it )
00433 {
00434
00435 if( (*it).equals( url, true ) )
00436 wantRecurseUrl = true;
00437 }
00438
00439 KFileTreeViewItem *nextChild = 0;
00440 kdDebug(250) << "Recursing " << url.prettyURL() << "? " << wantRecurseUrl << endl;
00441
00442 if( wantRecurseUrl && currParent )
00443 {
00444
00445
00446
00447
00448 nextChild = static_cast<KFileTreeViewItem*>
00449 (static_cast<QListViewItem*>(currParent)->firstChild());
00450
00451 if( ! nextChild )
00452 {
00453
00454 kdDebug( 250 ) << "No children to recuse" << endl;
00455 }
00456
00457
00458
00459
00460 m_openChildrenURLs.remove(url);
00461 }
00462
00463 if( nextChild )
00464 {
00465
00466
00467
00468
00469
00470
00471 while( nextChild )
00472 {
00473 if( nextChild->isDir() && ! nextChild->alreadyListed())
00474 {
00475 KFileItem *kfi = nextChild->fileItem();
00476 if( kfi && kfi->isReadable())
00477 {
00478 KURL recurseUrl = kfi->url();
00479 kdDebug(250) << "Starting to recurse NOW " << recurseUrl.prettyURL() << endl;
00480 openURL( recurseUrl, true );
00481 }
00482 }
00483 nextChild = static_cast<KFileTreeViewItem*>(static_cast<QListViewItem*>(nextChild->nextSibling()));
00484
00485 }
00486 }
00487 }
00488 else
00489 {
00490 kdDebug(250) << "skipping to recurse in complete-slot" << endl;
00491 }
00492 }
00493
00494
00495 bool KFileTreeBranch::populate( const KURL& url, KFileTreeViewItem *currItem )
00496 {
00497 bool ret = false;
00498 if( ! currItem )
00499 return ret;
00500
00501 kdDebug(250) << "Populating <" << url.prettyURL() << ">" << endl;
00502
00503
00504 if( m_recurseChildren )
00505 {
00506 m_openChildrenURLs.append( url );
00507 kdDebug(250) << "Appending to list " << url.prettyURL() << endl;
00508 }
00509
00510 if( ! currItem->alreadyListed() )
00511 {
00512
00513 ret = openURL( url, true );
00514 }
00515 else
00516 {
00517 kdDebug(250) << "Children already existing in treeview!" << endl;
00518 slCompleted( url );
00519 ret = true;
00520 }
00521 return ret;
00522 }
00523
00524 void KFileTreeBranch::virtual_hook( int id, void* data )
00525 { KDirLister::virtual_hook( id, data ); }
00526
00527 #include "kfiletreebranch.moc"
00528