kfiletreebranch.cpp Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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 void KFileTreeBranch::deleteChildrenOf( QListViewItem *parent )
    00314 {
    00315     // for some strange reason, slotDirlisterClearURL() sometimes calls us
    00316     // with a 0L parent.
    00317     if ( !parent )
    00318         return;
    00319
    00320     QListViewItem *child = parent->firstChild();
    00321     QListViewItem *next = child;
    00322
    00323     while( child )
    00324     {
    00325         next = child->nextSibling();
    00326         delete child;
    00327         child  = next;
    00328     }
    00329 }
    00330
    00331 void KFileTreeBranch::slotRedirect( const KURL& oldUrl, const KURL&newUrl )
    00332 {
    00333     if( oldUrl.equals( m_startURL, true ))
    00334     {
    00335         m_startURL = newUrl;
    00336     }
    00337 }
    00338
    00339 KFileTreeViewItem* KFileTreeBranch::findTVIByURL( const KURL& url )
    00340 {
    00341     KFileTreeViewItem *resultItem = 0;
    00342
    00343     if( m_startURL.equals(url, true) )
    00344     {
    00345         kdDebug(250) << "findByURL: Returning root as a parent !" << endl;
    00346         resultItem = m_root;
    00347     }
    00348     else if( m_lastFoundURL.equals( url, true ))
    00349     {
    00350         kdDebug(250) << "findByURL: Returning from lastFoundURL!" << endl;
    00351         resultItem = m_lastFoundItem;
    00352     }
    00353     else
    00354     {
    00355         kdDebug(250) << "findByURL: searching by dirlister: " << url.url() << endl;
    00356
    00357         KFileItem *it = findByURL( url );
    00358
    00359         if( it )
    00360         {
    00361             resultItem = static_cast<KFileTreeViewItem*>(it->extraData(this));
    00362             m_lastFoundItem = resultItem;
    00363             m_lastFoundURL = url;
    00364         }
    00365     }
    00366
    00367     return( resultItem );
    00368 }
    00369
    00370
    00371 void KFileTreeBranch::slCompleted( const KURL& url )
    00372 {
    00373     kdDebug(250) << "SlotCompleted hit for " << url.prettyURL() << endl;
    00374     KFileTreeViewItem *currParent = findTVIByURL( url );
    00375     if( ! currParent ) return;
    00376
    00377     kdDebug(250) << "current parent " << currParent << " is already listed: "
    00378                  << currParent->alreadyListed() << endl;
    00379
    00380     emit( populateFinished(currParent));
    00381     emit( directoryChildCount(currParent, currParent->childCount()));
    00382
    00383     /* This is a walk through the children of the last populated directory.
    00384      * Here we start the dirlister on every child of the dir and wait for its
    00385      * finish. When it has finished, we go to the next child.
    00386      * This must be done for non local file systems in dirOnly- and Full-Mode
    00387      * and for local file systems only in full mode, because the stat trick
    00388      * (see addItem-Method) does only work for dirs, not for files in the directory.
    00389      */
    00390     /* Set bit that the parent dir was listed completely */
    00391     currParent->setListed(true);
    00392
    00393     kdDebug(250) << "recurseChildren: " << m_recurseChildren << endl;
    00394     kdDebug(250) << "isLocalFile: " << m_startURL.isLocalFile() << endl;
    00395     kdDebug(250) << "dirOnlyMode: " << dirOnlyMode() << endl;
    00396
    00397
    00398     if( m_recurseChildren && (!m_startURL.isLocalFile() || ! dirOnlyMode()) )
    00399     {
    00400         bool wantRecurseUrl = false;
    00401         /* look if the url is in the list for url to recurse */
    00402         for ( KURL::List::Iterator it = m_openChildrenURLs.begin();
    00403               it != m_openChildrenURLs.end(); ++it )
    00404         {
    00405             /* it is only interesting that the url _is_in_ the list. */
    00406             if( (*it).equals( url, true ) )
    00407                 wantRecurseUrl = true;
    00408         }
    00409
    00410         KFileTreeViewItem    *nextChild = 0;
    00411         kdDebug(250) << "Recursing " << url.prettyURL() << "? " << wantRecurseUrl << endl;
    00412
    00413         if( wantRecurseUrl && currParent )
    00414         {
    00415
    00416             /* now walk again through the tree and populate the children to get +-signs */
    00417             /* This is the starting point. The visible folder has finished,
    00418                processing the children has not yet started */
    00419             nextChild = static_cast<KFileTreeViewItem*>
    00420                         (static_cast<QListViewItem*>(currParent)->firstChild());
    00421
    00422             if( ! nextChild )
    00423             {
    00424                 /* This happens if there is no child at all */
    00425                 kdDebug( 250 ) << "No children to recuse" << endl;
    00426             }
    00427
    00428             /* Since we have listed the children to recurse, we can remove the entry
    00429              * in the list of the URLs to see the children.
    00430              */
    00431             m_openChildrenURLs.remove(url);
    00432         }
    00433
    00434         if( nextChild ) /* This implies that idx > -1 */
    00435         {
    00436             /* Next child is defined. We start a dirlister job on every child item
    00437              * which is a directory to find out how much children are in the child
    00438              * of the last opened dir
    00439              */
    00440
    00441             /* Skip non directory entries */
    00442             while( nextChild )
    00443             {
    00444                 if( nextChild->isDir() && ! nextChild->alreadyListed())
    00445                 {
    00446                     KFileItem *kfi = nextChild->fileItem();
    00447                     if( kfi && kfi->isReadable())
    00448                     {
    00449                         KURL recurseUrl = kfi->url();
    00450                         kdDebug(250) << "Starting to recurse NOW " << recurseUrl.prettyURL() << endl;
    00451                         openURL( recurseUrl, true );
    00452                     }
    00453                 }
    00454                 nextChild = static_cast<KFileTreeViewItem*>(static_cast<QListViewItem*>(nextChild->nextSibling()));
    00455                 // kdDebug(250) << "Next child " << m_nextChild << endl;
    00456             }
    00457         }
    00458     }
    00459     else
    00460     {
    00461         kdDebug(250) << "skipping to recurse in complete-slot" << endl;
    00462     }
    00463 }
    00464
    00465 /* This slot is called when a treeviewitem is expanded in the gui */
    00466 bool KFileTreeBranch::populate( const KURL& url,  KFileTreeViewItem *currItem )
    00467 {
    00468     bool ret = false;
    00469     if( ! currItem )
    00470         return ret;
    00471
    00472     kdDebug(250) << "Populating <" << url.prettyURL() << ">" << endl;
    00473
    00474     /* Add this url to the list of urls to recurse for children */
    00475     if( m_recurseChildren )
    00476     {
    00477         m_openChildrenURLs.append( url );
    00478         kdDebug(250) << "Appending to list " << url.prettyURL() << endl;
    00479     }
    00480
    00481     if( ! currItem->alreadyListed() )
    00482     {
    00483         /* start the lister */
    00484         ret = openURL( url, true );
    00485     }
    00486     else
    00487     {
    00488         kdDebug(250) << "Children already existing in treeview!" << endl;
    00489         slCompleted( url );
    00490         ret = true;
    00491     }
    00492     return ret;
    00493 }
    00494
    00495 void KFileTreeBranch::virtual_hook( int id, void* data )
    00496 { KDirLister::virtual_hook( id, data ); }
    00497
    00498 #include "kfiletreebranch.moc"
    00499

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:13:34 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001