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 
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 
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     
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     
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     
00117 
00118 
00119     KURL url = item->url();
00120     
00121     KURL dirUrl( url );
00122     dirUrl.setFileName( QString::null );
00123     
00124 
00125     parent  = findTVIByURL( dirUrl );
00126     
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         
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             
00154             if( !m_showExtensions && !currItem->isDir() )   
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         
00165         
00166         
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             
00172 
00173 
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;  
00179                 kdDebug(250) << "stat succeeded, hardlinks: " << hardLinks << endl;
00180                 
00181                 
00182                 
00183 
00184                 if( hardLinks != 2 )
00185                 {
00186                     newKFTVI->setExpandable(true);
00187                 }
00188                 else
00189                 {
00190                     newKFTVI->setExpandable(false);
00191                 }
00192                 if( hardLinks >= 2 ) 
00193                 {
00194                     kdDebug(250) << "Emitting for " << url.prettyURL() << endl;
00195                     emit( directoryChildCount( newKFTVI, hardLinks-2)); 
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 
00248 
00249 
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     
00287     
00288     m_openChildrenURLs.remove( url);
00289 
00290     
00291     emit populateFinished( findTVIByURL(url));
00292 }
00293 
00294 void KFileTreeBranch::slotDirlisterClear()
00295 {
00296     kdDebug(250)<< "*** Clear all !" << endl;
00297     
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     
00317     
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     
00378 
00379 
00380 
00381 
00382 
00383 
00384     
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         
00396         for ( KURL::List::Iterator it = m_openChildrenURLs.begin();
00397               it != m_openChildrenURLs.end(); ++it )
00398         {
00399             
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             
00411             
00412 
00413             nextChild = static_cast<KFileTreeViewItem*>
00414                         (static_cast<QListViewItem*>(currParent)->firstChild());
00415 
00416             if( ! nextChild )
00417             {
00418                 
00419                 kdDebug( 250 ) << "No children to recuse" << endl;
00420             }
00421 
00422             
00423 
00424 
00425             m_openChildrenURLs.remove(url);
00426         }
00427 
00428         if( nextChild ) 
00429         {
00430             
00431 
00432 
00433 
00434 
00435             
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                 
00450             }
00451         }
00452     }
00453     else
00454     {
00455         kdDebug(250) << "skipping to recurse in complete-slot" << endl;
00456     }
00457 }
00458 
00459 
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     
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         
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