kio Library: kfiletreebranch.cpp Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | 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 #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 /* --- KFileTreeViewToplevelItem --- */
    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     /* if non exists, create one */
    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     /* set the parent correct if it is zero. */
    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     /* If it is a directory, check, if it exists in the dict. If not, go one up
    00121      * and check again.
    00122      */
    00123     KURL url = item->url();
    00124     // kdDebug(250) << "Item's url is " << url.prettyURL() << endl;
    00125     KURL dirUrl( url );
    00126     dirUrl.setFileName( QString::null );
    00127     // kdDebug(250) << "Directory url is " << dirUrl.prettyURL() << endl;
    00128
    00129     parent  = findTVIByURL( dirUrl );
    00130     // kdDebug(250) << "Returning as parent item <" << parent <<  ">" << endl;
    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         /* Only create a new KFileTreeViewItem if it does not yet exist */
    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                 // TODO: Don't fail if parentItem == 0
    00176                 ++it;
    00177                 continue;
    00178             }
    00179             currItem->setExtraData( this, newKFTVI );
    00180
    00181             /* Cut off the file extension in case it is not a directory */
    00182             if( !m_showExtensions && !currItem->isDir() )   /* Need to cut the extension */
    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         /* Now try to find out if there are children for dirs in the treeview */
    00193         /* This stats a directory on the local file system and checks the */
    00194         /* hardlink entry in the stat-buf. This works only for local directories. */
    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             /* do the stat trick of Carsten. The problem is, that the hardlink
    00200              *  count only contains directory links. Thus, this method only seem
    00201              * to work in dir-only mode */
    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;  /* Count of dirs */
    00207                 kdDebug(250) << "stat succeeded, hardlinks: " << hardLinks << endl;
    00208                 // If the link count is > 2, the directory likely has subdirs. If it's < 2
    00209                 // it's something weird like a mounted SMB share. In that case we don't know
    00210                 // if there are subdirs, thus show it as expandable.
    00211
    00212                 if( hardLinks != 2 )
    00213                 {
    00214                     newKFTVI->setExpandable(true);
    00215                 }
    00216                 else
    00217                 {
    00218                     newKFTVI->setExpandable(false);
    00219                 }
    00220                 if( hardLinks >= 2 ) // "Normal" directory with subdirs
    00221                 {
    00222                     kdDebug(250) << "Emitting for " << url.prettyURL() << endl;
    00223                     emit( directoryChildCount( newKFTVI, hardLinks-2)); // parentItem, hardLinks-1 ));
    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  * The signal that tells that a directory was deleted may arrive before the signal
    00276  * for its children arrive. Thus, we must walk through the children of a dir and
    00277  * remove them before removing the dir itself.
    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     // ### anything else to do?
    00320     // remove the url from the childrento-recurse-list
    00321     m_openChildrenURLs.remove( url);
    00322
    00323     // stop animations etc.
    00324     KFileTreeViewItem *item = findTVIByURL(url);
    00325     if (!item) return; // Uh oh...
    00326     emit populateFinished(item);
    00327 }
    00328
    00329 void KFileTreeBranch::slotDirlisterClear()
    00330 {
    00331     kdDebug(250)<< "*** Clear all !" << endl;
    00332     /* this slots needs to clear all listed items, but NOT the root item */
    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     // for some strange reason, slotDirlisterClearURL() sometimes calls us
    00352     // with a 0L parent.
    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     /* This is a walk through the children of the last populated directory.
    00413      * Here we start the dirlister on every child of the dir and wait for its
    00414      * finish. When it has finished, we go to the next child.
    00415      * This must be done for non local file systems in dirOnly- and Full-Mode
    00416      * and for local file systems only in full mode, because the stat trick
    00417      * (see addItem-Method) does only work for dirs, not for files in the directory.
    00418      */
    00419     /* Set bit that the parent dir was listed completely */
    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         /* look if the url is in the list for url to recurse */
    00431         for ( KURL::List::Iterator it = m_openChildrenURLs.begin();
    00432               it != m_openChildrenURLs.end(); ++it )
    00433         {
    00434             /* it is only interesting that the url _is_in_ the list. */
    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             /* now walk again through the tree and populate the children to get +-signs */
    00446             /* This is the starting point. The visible folder has finished,
    00447                processing the children has not yet started */
    00448             nextChild = static_cast<KFileTreeViewItem*>
    00449                         (static_cast<QListViewItem*>(currParent)->firstChild());
    00450
    00451             if( ! nextChild )
    00452             {
    00453                 /* This happens if there is no child at all */
    00454                 kdDebug( 250 ) << "No children to recuse" << endl;
    00455             }
    00456
    00457             /* Since we have listed the children to recurse, we can remove the entry
    00458              * in the list of the URLs to see the children.
    00459              */
    00460             m_openChildrenURLs.remove(url);
    00461         }
    00462
    00463         if( nextChild ) /* This implies that idx > -1 */
    00464         {
    00465             /* Next child is defined. We start a dirlister job on every child item
    00466              * which is a directory to find out how much children are in the child
    00467              * of the last opened dir
    00468              */
    00469
    00470             /* Skip non directory entries */
    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                 // kdDebug(250) << "Next child " << m_nextChild << endl;
    00485             }
    00486         }
    00487     }
    00488     else
    00489     {
    00490         kdDebug(250) << "skipping to recurse in complete-slot" << endl;
    00491     }
    00492 }
    00493
    00494 /* This slot is called when a treeviewitem is expanded in the gui */
    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     /* Add this url to the list of urls to recurse for children */
    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         /* start the lister */
    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

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:59 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003