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

KDE3Support

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 "kfiletreebranch.h"
00022 
00023 #include <QtCore/QFile>
00024 
00025 #include <kfileitem.h>
00026 #include <kdebug.h>
00027 #include <kde_file.h>
00028 
00029 #include <sys/types.h>
00030 #include <sys/stat.h>
00031 #include <unistd.h>
00032 
00033 /* --- K3FileTreeViewToplevelItem --- */
00034 KFileTreeBranch::KFileTreeBranch( K3FileTreeView *parent, const KUrl& url,
00035                                   const QString& name,
00036                   const QPixmap& pix, bool showHidden,
00037                   K3FileTreeViewItem *branchRoot )
00038 
00039     : KDirLister(),
00040       m_root( branchRoot ),
00041       m_startURL( url ),
00042       m_name ( name ),
00043       m_rootIcon( pix ),
00044       m_openRootIcon( pix ),
00045       m_recurseChildren(true),
00046       m_showExtensions(true)
00047 {
00048     kDebug( 250) << "Creating branch for url " << url.prettyUrl();
00049 
00050     /* if non exists, create one */
00051     if( ! branchRoot )
00052     {
00053         m_root =  new K3FileTreeViewItem( parent,
00054                                           KFileItem( url, "inode/directory",
00055                                                         S_IFDIR  ),
00056                                          this );
00057     }
00058 
00059     m_root->setExpandable( true );
00060     m_root->setPixmap( 0, pix );
00061     m_root->setText( 0, name );
00062 
00063     setShowingDotFiles( showHidden );
00064 
00065     connect( this, SIGNAL( refreshItems(const QList<QPair<KFileItem, KFileItem> >&)),
00066              this, SLOT  ( slotRefreshItems( const QList<QPair<KFileItem, KFileItem> >& )));
00067 
00068     connect( this, SIGNAL( newItems(const KFileItemList&)),
00069              this, SLOT  ( addItems( const KFileItemList& )));
00070 
00071     connect( this, SIGNAL( completed(const KUrl& )),
00072              this,   SLOT(slCompleted(const KUrl&)));
00073 
00074     connect( this, SIGNAL( started( const KUrl& )),
00075              this,   SLOT( slotListerStarted( const KUrl& )));
00076 
00077     connect( this, SIGNAL( deleteItem( const KFileItem& )),
00078              this,   SLOT( slotDeleteItem( const KFileItem& )));
00079 
00080     connect( this, SIGNAL( canceled(const KUrl&) ),
00081              this,   SLOT( slotCanceled(const KUrl&) ));
00082 
00083     connect( this, SIGNAL( clear()),
00084              this, SLOT( slotDirlisterClear()));
00085 
00086     connect( this, SIGNAL( clear(const KUrl&)),
00087              this, SLOT( slotDirlisterClearUrl(const KUrl&)));
00088 
00089     connect( this, SIGNAL( redirection( const KUrl& , const KUrl& ) ),
00090              this, SLOT( slotRedirect( const KUrl&, const KUrl& )));
00091 
00092     m_openChildrenURLs.append( url );
00093 }
00094 
00095 KUrl KFileTreeBranch::rootUrl() const
00096 {
00097     return( m_startURL );
00098 }
00099 
00100 void KFileTreeBranch::setRoot( K3FileTreeViewItem *r )
00101 {
00102     m_root = r;
00103 }
00104 
00105 K3FileTreeViewItem *KFileTreeBranch::root( )
00106 {
00107     return( m_root );
00108 }
00109 
00110 QString KFileTreeBranch::name() const
00111 {
00112     return( m_name );
00113 }
00114 
00115 void KFileTreeBranch::setName( const QString n )
00116 {
00117     m_name = n;
00118 }
00119 
00120 QPixmap KFileTreeBranch::pixmap() const
00121 {
00122     return m_rootIcon;
00123 }
00124 
00125 QPixmap KFileTreeBranch::openPixmap() const
00126 {
00127     return m_openRootIcon;
00128 }
00129 
00130 void KFileTreeBranch::setOpen( bool setopen )
00131 {
00132     if ( root() ) {
00133         root()->setOpen( setopen );
00134     }
00135 }
00136 
00137 void KFileTreeBranch::setOpenPixmap( const QPixmap& pix )
00138 {
00139     m_openRootIcon = pix;
00140 
00141     if( root()->isOpen())
00142     {
00143         root()->setPixmap( 0, pix );
00144     }
00145 }
00146 
00147 void KFileTreeBranch::slotListerStarted( const KUrl &url )
00148 {
00149     /* set the parent correct if it is zero. */
00150     kDebug( 250) << "Starting to list " << url.prettyUrl();
00151 }
00152 
00153 
00154 K3FileTreeViewItem* KFileTreeBranch::treeItemForFileItem(const KFileItem &it)
00155 {
00156     return
00157         const_cast<K3FileTreeViewItem *>(
00158         static_cast<const K3FileTreeViewItem*>(it.extraData(this)));
00159 }
00160 
00161 K3FileTreeViewItem *KFileTreeBranch::parentKFTVItem( const KFileItem &item )
00162 {
00163     K3FileTreeViewItem *parent = 0;
00164 
00165     if( item.isNull() ) return 0;
00166 
00167     /* If it is a directory, check, if it exists in the dict. If not, go one up
00168      * and check again.
00169      */
00170     KUrl url = item.url();
00171     // kDebug(250) << "Item's url is " << url.prettyUrl();
00172     KUrl dirUrl( url );
00173     dirUrl.setFileName( QString() );
00174     // kDebug(250) << "Directory url is " << dirUrl.prettyUrl();
00175 
00176     parent  = findTVIByUrl( dirUrl );
00177     // kDebug(250) << "Returning as parent item <" << parent <<  ">";
00178     return( parent );
00179 }
00180 
00181 
00182 void KFileTreeBranch::slotRefreshItems( const QList<QPair<KFileItem, KFileItem> > &list )
00183 {
00184     kDebug(250) << "Refreshing " << list.count() << " items !";
00185 
00186     for ( int i = 0; i < list.count(); ++i )
00187     {
00188         const KFileItem fileItem = list[ i ].second;
00189 
00190         K3FileTreeViewItem *item = findTVIByUrl(fileItem.url());
00191         if (item) {
00192             item->setPixmap(0, item->fileItem().pixmap( KIconLoader::SizeSmall ));
00193             item->setText( 0, item->fileItem().text());
00194         }
00195     }
00196 }
00197 
00198 void KFileTreeBranch::addItems( const KFileItemList& list )
00199 {
00200     kDebug(250) << "Adding " << list.count() << " items !";
00201     K3FileTreeViewItemList treeViewItList;
00202     K3FileTreeViewItem *parentItem = 0;
00203 
00204     KFileItemList::const_iterator kit = list.begin();
00205     const KFileItemList::const_iterator kend = list.end();
00206     for ( ; kit != kend; ++kit )
00207     {
00208         KFileItem currItem = *kit;
00209         parentItem = parentKFTVItem( currItem );
00210 
00211         /* Only create a new K3FileTreeViewItem if it does not yet exist */
00212         K3FileTreeViewItem *newKFTVI = treeItemForFileItem(currItem);
00213 
00214         if( ! newKFTVI )
00215         {
00216             newKFTVI = createTreeViewItem( parentItem, currItem );
00217             if (!newKFTVI)
00218             {
00219                 // TODO: Don't fail if parentItem == 0
00220                 continue;
00221             }
00222             currItem.setExtraData( this, newKFTVI );
00223 
00224             /* Cut off the file extension in case it is not a directory */
00225             if( !m_showExtensions && !currItem.isDir() )    /* Need to cut the extension */
00226             {
00227                 QString name = currItem.text();
00228                 int mPoint = name.lastIndexOf( '.' );
00229                 if( mPoint > 0 )
00230                     name = name.left( mPoint );
00231                 newKFTVI->setText( 0, name );
00232             }
00233         }
00234 
00235         /* Now try to find out if there are children for dirs in the treeview */
00236         /* This stats a directory on the local file system and checks the */
00237         /* hardlink entry in the stat-buf. This works only for local directories. */
00238         if( dirOnlyMode() && !m_recurseChildren && currItem.isLocalFile( ) && currItem.isDir() )
00239         {
00240             KUrl url = currItem.url();
00241             QString filename = url.directory( KUrl::ObeyTrailingSlash ) + url.fileName();
00242             /* do the stat trick of Carsten. The problem is, that the hardlink
00243              *  count only contains directory links. Thus, this method only seem
00244              * to work in dir-only mode */
00245             kDebug(250) << "Doing stat on " << filename;
00246             KDE_struct_stat statBuf;
00247             if( KDE::stat( filename , &statBuf ) == 0 )
00248             {
00249                 int hardLinks = statBuf.st_nlink;  /* Count of dirs */
00250                 kDebug(250) << "stat succeeded, hardlinks: " << hardLinks;
00251                 // If the link count is > 2, the directory likely has subdirs. If it's < 2
00252                 // it's something weird like a mounted SMB share. In that case we don't know
00253                 // if there are subdirs, thus show it as expandable.
00254 
00255                 if( hardLinks != 2 )
00256                 {
00257                     newKFTVI->setExpandable(true);
00258                 }
00259                 else
00260                 {
00261                     newKFTVI->setExpandable(false);
00262                 }
00263                 if( hardLinks >= 2 ) // "Normal" directory with subdirs
00264                 {
00265                     kDebug(250) << "Emitting for " << url.prettyUrl();
00266                     emit( directoryChildCount( newKFTVI, hardLinks-2)); // parentItem, hardLinks-1 ));
00267                 }
00268             }
00269             else
00270             {
00271                 kDebug(250) << "stat of " << filename << " failed !";
00272             }
00273         }
00274         treeViewItList.append( newKFTVI );
00275     }
00276 
00277     emit newTreeViewItems( this, treeViewItList );
00278 }
00279 
00280 K3FileTreeViewItem* KFileTreeBranch::createTreeViewItem( K3FileTreeViewItem *parent,
00281                             const KFileItem &fileItem )
00282 {
00283     K3FileTreeViewItem  *tvi = 0;
00284     if( parent && !fileItem.isNull() )
00285     {
00286         tvi = new K3FileTreeViewItem( parent,
00287                                      fileItem,
00288                                      this );
00289     }
00290     else
00291     {
00292         kDebug(250) << "createTreeViewItem: Have no parent";
00293     }
00294     return( tvi );
00295 }
00296 
00297 void KFileTreeBranch::setChildRecurse( bool t )
00298 {
00299     m_recurseChildren = t;
00300     if( t == false )
00301         m_openChildrenURLs.clear();
00302 }
00303 
00304 bool KFileTreeBranch::childRecurse()
00305 {
00306     return m_recurseChildren;
00307 }
00308 
00309 
00310 void KFileTreeBranch::setShowExtensions( bool visible )
00311 {
00312     m_showExtensions = visible;
00313 }
00314 
00315 bool KFileTreeBranch::showExtensions( ) const
00316 {
00317     return( m_showExtensions );
00318 }
00319 
00320 /*
00321  * The signal that tells that a directory was deleted may arrive before the signal
00322  * for its children arrive. Thus, we must walk through the children of a dir and
00323  * remove them before removing the dir itself.
00324  */
00325 void KFileTreeBranch::slotDeleteItem( const KFileItem &it )
00326 {
00327     if( it.isNull() ) return;
00328     kDebug(250) << "Slot Delete Item hitted for " << it.url().prettyUrl();
00329 
00330     K3FileTreeViewItem *kfti = treeItemForFileItem(it);
00331 
00332     if( kfti )
00333     {
00334         kDebug( 250 ) << "Child count: " << kfti->childCount();
00335         if( kfti->childCount() > 0 )
00336         {
00337             K3FileTreeViewItem *child = static_cast<K3FileTreeViewItem*>(kfti->firstChild());
00338 
00339             while( child )
00340             {
00341                 kDebug(250) << "Calling child to be deleted !";
00342                 K3FileTreeViewItem *nextChild = static_cast<K3FileTreeViewItem*>(child->nextSibling());
00343                 slotDeleteItem( child->fileItem());
00344                 child = nextChild;
00345             }
00346         }
00347 
00348         kDebug(250) << "Found corresponding K3FileTreeViewItem";
00349         if( m_lastFoundURL.equals(it.url(), KUrl::CompareWithoutTrailingSlash ))
00350         {
00351           m_lastFoundURL = KUrl();
00352           m_lastFoundItem = 0L;
00353         }
00354         delete( kfti );
00355     }
00356     else
00357     {
00358         kDebug(250) << "Error: kfiletreeviewitem: "<< kfti;
00359     }
00360 }
00361 
00362 
00363 void KFileTreeBranch::slotCanceled( const KUrl& url )
00364 {
00365     // ### anything else to do?
00366     // remove the url from the childrento-recurse-list
00367     m_openChildrenURLs.removeAll( url);
00368 
00369     // stop animations etc.
00370     K3FileTreeViewItem *item = findTVIByUrl(url);
00371     if (!item) return; // Uh oh...
00372     emit populateFinished(item);
00373 }
00374 
00375 void KFileTreeBranch::slotDirlisterClear()
00376 {
00377     kDebug(250)<< "*** Clear all !";
00378     /* this slots needs to clear all listed items, but NOT the root item */
00379     if( m_root )
00380         deleteChildrenOf( m_root );
00381 }
00382 
00383 void KFileTreeBranch::slotDirlisterClearUrl( const KUrl& url )
00384 {
00385     kDebug(250)<< "*** Clear for URL !" << url.prettyUrl();
00386     const KFileItem item = findByUrl( url );
00387     if( !item.isNull() )
00388     {
00389         K3FileTreeViewItem *ftvi = treeItemForFileItem(item);
00390         deleteChildrenOf( ftvi );
00391     }
00392 }
00393 
00394 void KFileTreeBranch::deleteChildrenOf( Q3ListViewItem *parent )
00395 {
00396     // for some strange reason, slotDirlisterClearURL() sometimes calls us
00397     // with a 0L parent.
00398     if ( !parent )
00399         return;
00400 
00401     while ( parent->firstChild() )
00402         delete parent->firstChild();
00403 }
00404 
00405 void KFileTreeBranch::slotRedirect( const KUrl& oldUrl, const KUrl&newUrl )
00406 {
00407   if( oldUrl.equals( m_startURL, KUrl::CompareWithoutTrailingSlash ))
00408     {
00409         m_startURL = newUrl;
00410     }
00411 }
00412 
00413 K3FileTreeViewItem* KFileTreeBranch::findTVIByUrl( const KUrl& url )
00414 {
00415     K3FileTreeViewItem *resultItem = 0;
00416 
00417     if( m_startURL.equals(url, KUrl::CompareWithoutTrailingSlash) )
00418     {
00419         kDebug(250) << "findByURL: Returning root as a parent !";
00420         resultItem = m_root;
00421     }
00422     else if( m_lastFoundURL.equals( url, KUrl::CompareWithoutTrailingSlash ))
00423     {
00424         kDebug(250) << "findByURL: Returning from lastFoundURL!";
00425         resultItem = m_lastFoundItem;
00426     }
00427     else
00428     {
00429         kDebug(250) << "findByURL: searching by dirlister: " << url.url();
00430 
00431         const KFileItem it = findByUrl( url );
00432 
00433         if( !it.isNull() )
00434         {
00435             resultItem = treeItemForFileItem(it);
00436             m_lastFoundItem = resultItem;
00437             m_lastFoundURL = url;
00438         }
00439     }
00440 
00441     return( resultItem );
00442 }
00443 
00444 
00445 void KFileTreeBranch::slCompleted( const KUrl& url )
00446 {
00447     kDebug(250) << "SlotCompleted hit for " << url.prettyUrl();
00448     K3FileTreeViewItem *currParent = findTVIByUrl( url );
00449     if( ! currParent ) return;
00450 
00451     kDebug(250) << "current parent " << currParent << " is already listed: "
00452                  << currParent->alreadyListed() << endl;
00453 
00454     emit( populateFinished(currParent));
00455     emit( directoryChildCount(currParent, currParent->childCount()));
00456 
00457     /* This is a walk through the children of the last populated directory.
00458      * Here we start the dirlister on every child of the dir and wait for its
00459      * finish. When it has finished, we go to the next child.
00460      * This must be done for non local file systems in dirOnly- and Full-Mode
00461      * and for local file systems only in full mode, because the stat trick
00462      * (see addItem-Method) does only work for dirs, not for files in the directory.
00463      */
00464     /* Set bit that the parent dir was listed completely */
00465     currParent->setListed(true);
00466 
00467     kDebug(250) << "recurseChildren: " << m_recurseChildren;
00468     kDebug(250) << "isLocalFile: " << m_startURL.isLocalFile();
00469     kDebug(250) << "dirOnlyMode: " << dirOnlyMode();
00470 
00471 
00472     if( m_recurseChildren && (!m_startURL.isLocalFile() || ! dirOnlyMode()) )
00473     {
00474         bool wantRecurseUrl = false;
00475         /* look if the url is in the list for url to recurse */
00476         for ( KUrl::List::Iterator it = m_openChildrenURLs.begin();
00477               it != m_openChildrenURLs.end(); ++it )
00478         {
00479             /* it is only interesting that the url _is_in_ the list. */
00480           if( (*it).equals( url, KUrl::CompareWithoutTrailingSlash ) )
00481                 wantRecurseUrl = true;
00482         }
00483 
00484         K3FileTreeViewItem    *nextChild = 0;
00485         kDebug(250) << "Recursing " << url.prettyUrl() << "? " << wantRecurseUrl;
00486 
00487         if( wantRecurseUrl && currParent )
00488         {
00489 
00490             /* now walk again through the tree and populate the children to get +-signs */
00491             /* This is the starting point. The visible folder has finished,
00492                processing the children has not yet started */
00493             nextChild = static_cast<K3FileTreeViewItem*>
00494                         (static_cast<Q3ListViewItem*>(currParent)->firstChild());
00495 
00496             if( ! nextChild )
00497             {
00498                 /* This happens if there is no child at all */
00499                 kDebug( 250 ) << "No children to recuse";
00500             }
00501 
00502             /* Since we have listed the children to recurse, we can remove the entry
00503              * in the list of the URLs to see the children.
00504              */
00505             m_openChildrenURLs.removeAll(url);
00506         }
00507 
00508         if( nextChild ) /* This implies that idx > -1 */
00509         {
00510             /* Next child is defined. We start a dirlister job on every child item
00511              * which is a directory to find out how much children are in the child
00512              * of the last opened dir
00513              */
00514 
00515             /* Skip non directory entries */
00516             while( nextChild )
00517             {
00518                 if( nextChild->isDir() && ! nextChild->alreadyListed())
00519                 {
00520                     const KFileItem kfi = nextChild->fileItem();
00521                     if( !kfi.isNull() && kfi.isReadable())
00522                     {
00523                         KUrl recurseUrl = kfi.url();
00524                         kDebug(250) << "Starting to recurse NOW " << recurseUrl.prettyUrl();
00525                         openUrl( recurseUrl, KDirLister::Keep );
00526                     }
00527                 }
00528                 nextChild = static_cast<K3FileTreeViewItem*>(nextChild->nextSibling());
00529                 // kDebug(250) << "Next child " << m_nextChild;
00530             }
00531         }
00532     }
00533     else
00534     {
00535         kDebug(250) << "skipping to recurse in complete-slot";
00536     }
00537 }
00538 
00539 /* This slot is called when a treeviewitem is expanded in the gui */
00540 bool KFileTreeBranch::populate( const KUrl& url,  K3FileTreeViewItem *currItem )
00541 {
00542     bool ret = false;
00543     if( ! currItem )
00544         return ret;
00545 
00546     kDebug(250) << "Populating <" << url.prettyUrl() << ">";
00547 
00548     /* Add this url to the list of urls to recurse for children */
00549     if( m_recurseChildren )
00550     {
00551         m_openChildrenURLs.append( url );
00552         kDebug(250) << "Appending to list " << url.prettyUrl();
00553     }
00554 
00555     if( ! currItem->alreadyListed() )
00556     {
00557         /* start the lister */
00558         ret = openUrl( url, KDirLister::Keep );
00559     }
00560     else
00561     {
00562         kDebug(250) << "Children already existing in treeview!";
00563         slCompleted( url );
00564         ret = true;
00565     }
00566     return ret;
00567 }
00568 
00569 #include "kfiletreebranch.moc"
00570 

KDE3Support

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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