• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kio

kfiletreebranch.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, 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 

kio

Skip menu "kio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal