File indexing completed on 2024-03-24 15:48:00
0001 /* This file is part of the KDEproject 0002 Copyright (C) 2000 David Faure <faure@kde.org> 0003 2000 Carsten Pfeiffer <pfeiffer@kde.org> 0004 2002 Klaas Freitag <freitag@suse.de> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License version 2 as published by the Free Software Foundation. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "filetreebranch.h" 0022 0023 #include <sys/types.h> 0024 #include <sys/stat.h> 0025 #include <unistd.h> 0026 0027 #include <qdir.h> 0028 #include <qmimedatabase.h> 0029 0030 #include <kfileitem.h> 0031 0032 #include "filetreeview.h" 0033 #include "libfiletree_logging.h" 0034 0035 0036 #undef DEBUG_LISTING 0037 #undef DEBUG_MAPPING 0038 0039 0040 FileTreeBranch::FileTreeBranch(FileTreeView *parent, 0041 const QUrl &url, 0042 const QString &name, 0043 const QIcon &pix, 0044 bool showHidden, 0045 FileTreeViewItem *branchRoot) 0046 : KCoreDirLister(parent), 0047 m_root(branchRoot), 0048 m_name(name), 0049 m_rootIcon(pix), 0050 m_openRootIcon(pix), 0051 m_lastFoundItem(nullptr), 0052 m_recurseChildren(true), 0053 m_showExtensions(true) 0054 { 0055 setObjectName("FileTreeBranch"); 0056 0057 QUrl u(url); 0058 if (u.isLocalFile()) { // for local files, 0059 QDir d(u.path()); // ensure path is canonical 0060 u.setPath(d.canonicalPath()); 0061 } 0062 m_startURL = u; 0063 qCDebug(LIBFILETREE_LOG) << "for" << u; 0064 0065 // if no root is specified, create a new one 0066 if (m_root == nullptr) m_root = new FileTreeViewItem(parent, 0067 KFileItem(u, "inode/directory", S_IFDIR), 0068 this); 0069 //m_root->setExpandable(true); 0070 //m_root->setFirstColumnSpanned(true); 0071 bool sb = blockSignals(true); // don't want setText() to signal 0072 m_root->setIcon(0, pix); 0073 m_root->setText(0, name); 0074 m_root->setToolTip(0, QString("%1 - %2").arg(name, u.url(QUrl::PreferLocalFile))); 0075 blockSignals(sb); 0076 0077 setShowHiddenFiles(showHidden); 0078 0079 connect(this, &KCoreDirLister::itemsAdded, this, &FileTreeBranch::slotItemsAdded); 0080 connect(this, &KCoreDirLister::itemsDeleted, this, &FileTreeBranch::slotItemsDeleted); 0081 connect(this, &KCoreDirLister::refreshItems, this, &FileTreeBranch::slotRefreshItems); 0082 connect(this, &KCoreDirLister::started, this, &FileTreeBranch::slotListerStarted); 0083 0084 connect(this, &KCoreDirLister::listingDirCompleted, this, &FileTreeBranch::slotListerCompleted); 0085 connect(this, &KCoreDirLister::listingDirCanceled, this, &FileTreeBranch::slotListerCanceled); 0086 connect(this, &KCoreDirLister::clearDir, this, &FileTreeBranch::slotListerClear); 0087 connect(this, &KCoreDirLister::clearDir, this, &FileTreeBranch::slotListerClearUrl); 0088 connect(this, QOverload<const QUrl &, const QUrl &>::of(&KCoreDirLister::redirection), this, &FileTreeBranch::slotRedirect); 0089 0090 m_openChildrenURLs.append(u); 0091 } 0092 0093 QUrl FileTreeBranch::rootUrl() const 0094 { 0095 QUrl u = m_startURL.adjusted(QUrl::StripTrailingSlash); 0096 u.setPath(u.path()+'/'); 0097 return (u); 0098 } 0099 0100 void FileTreeBranch::setRoot(FileTreeViewItem *r) 0101 { 0102 m_root = r; 0103 } 0104 0105 FileTreeViewItem *FileTreeBranch::root() const 0106 { 0107 return (m_root); 0108 } 0109 0110 QString FileTreeBranch::name() const 0111 { 0112 return (m_name); 0113 } 0114 0115 void FileTreeBranch::setName(const QString &newName) 0116 { 0117 m_name = newName; 0118 } 0119 0120 QIcon FileTreeBranch::pixmap() const 0121 { 0122 return (m_rootIcon); 0123 } 0124 0125 QIcon FileTreeBranch::openPixmap() const 0126 { 0127 return (m_openRootIcon); 0128 } 0129 0130 void FileTreeBranch::setOpen(bool open) 0131 { 0132 if (root() != nullptr) { 0133 root()->setExpanded(open); 0134 } 0135 } 0136 0137 void FileTreeBranch::setOpenPixmap(const QIcon &pix) 0138 { 0139 m_openRootIcon = pix; 0140 if (root()->isExpanded()) { 0141 root()->setIcon(0, pix); 0142 } 0143 } 0144 0145 void FileTreeBranch::slotListerStarted(const QUrl &url) 0146 { 0147 #ifdef DEBUG_LISTING 0148 qCDebug(LIBFILETREE_LOG) << "lister started for" << url; 0149 #endif // DEBUG_LISTING 0150 0151 FileTreeViewItem *item = findItemByUrl(url); 0152 if (item != nullptr) { 0153 emit populateStarted(item); 0154 } 0155 } 0156 0157 // Renames seem to be emitted from KDirLister as a delete of the old followed 0158 // by an add of the new. Therefore there is no need to check for renaming here. 0159 0160 void FileTreeBranch::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &list) 0161 { 0162 #ifdef DEBUG_LISTING 0163 qCDebug(LIBFILETREE_LOG) << "Refreshing" << list.count() << "items"; 0164 #endif // DEBUG_LISTING 0165 0166 FileTreeViewItemList treeViewItList; // tree view items updated 0167 for (int i = 0; i < list.count(); ++i) { 0168 const KFileItem fi2 = list[i].second; // not interested in the first 0169 #ifdef DEBUG_LISTING 0170 qCDebug(LIBFILETREE_LOG) << fi2.url(); 0171 #endif // DEBUG_LISTING 0172 FileTreeViewItem *item = findItemByUrl(fi2.url()); 0173 if (item != nullptr) { 0174 treeViewItList.append(item); 0175 item->setIcon(0, QIcon::fromTheme(fi2.iconName())); 0176 item->setText(0, fi2.text()); 0177 } 0178 } 0179 0180 if (treeViewItList.count() > 0) { 0181 emit changedTreeViewItems(this, treeViewItList); 0182 } 0183 } 0184 0185 // This would never work in KDE4. It relies on being able to set the 0186 // KFileItem's extra data to hold its corresponding tree item pointer, 0187 // but since now KFileItem values (not pointers/references) are passed 0188 // around it is not possible to modify the KDirLister's internal KFileItem. 0189 // 0190 // Use findItemByUrl(fi.url()) instead. 0191 // 0192 //FileTreeViewItem *FileTreeBranch::treeItemForFileItem(const KFileItem &fi) 0193 //{ 0194 // if (fi.isNull()) return (nullptr); 0195 // //qCDebug(LIBFILETREE_LOG) << "for" << fi.url(); 0196 // FileTreeViewItem *ftvi = static_cast<FileTreeViewItem *>(const_cast<void *>(fi.extraData(this))); 0197 // return (ftvi); 0198 //} 0199 0200 FileTreeViewItem *FileTreeBranch::findItemByUrl(const QUrl &url) 0201 { 0202 FileTreeViewItem *resultItem = nullptr; 0203 0204 if (url == m_lastFoundUrl) { // most likely and fastest first 0205 #ifdef DEBUG_MAPPING 0206 qCDebug(LIBFILETREE_LOG) << "Found as last" << url; 0207 #endif 0208 return (m_lastFoundItem); // no more to do 0209 } else if (url == m_startURL) { // see if is the root 0210 #ifdef DEBUG_MAPPING 0211 qCDebug(LIBFILETREE_LOG) << "Found as root" << url; 0212 #endif 0213 resultItem = m_root; 0214 } else if (m_itemMap.contains(url)) { // see if in our map 0215 #ifdef DEBUG_MAPPING 0216 qCDebug(LIBFILETREE_LOG) << "Found in map" << url; 0217 #endif 0218 resultItem = m_itemMap[url]; 0219 } else { // need to ask the lister 0220 // See comments on the removed treeItemForFileItem() above. 0221 // We should never get here, the TVImap should have the data for 0222 // every item that we create. 0223 // 0224 ////qCDebug(LIBFILETREE_LOG) << "searching dirlister for" << url; 0225 //const KFileItem it = findByUrl(url); 0226 //if (!it.isNull() ) 0227 //{ 0228 // //qCDebug(LIBFILETREE_LOG) << "found item url" << it.url(); 0229 // resultItem = treeItemForFileItem(it); 0230 //} 0231 0232 #ifdef DEBUG_MAPPING 0233 qCDebug(LIBFILETREE_LOG) << "Not found" << url; 0234 #endif 0235 } 0236 0237 if (resultItem != nullptr) { // found something 0238 m_lastFoundItem = resultItem; // cache for next time 0239 m_lastFoundUrl = url; // path this applies to 0240 } 0241 0242 return (resultItem); 0243 } 0244 0245 // Find an item by a relative path. If the branch is known, this 0246 // saves having to convert an input path into an URL and then doing 0247 // lots of comparisons on it as above. 0248 FileTreeViewItem *FileTreeBranch::findItemByPath(const QString &path) 0249 { 0250 #ifdef DEBUG_MAPPING 0251 qCDebug(LIBFILETREE_LOG) << path; 0252 #endif 0253 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) 0254 const QStringList pathSplit = path.split('/', Qt::SkipEmptyParts); 0255 #else 0256 const QStringList pathSplit = path.split('/', QString::SkipEmptyParts); 0257 #endif 0258 FileTreeViewItem *item = m_root; 0259 0260 for (const QString &part : pathSplit) 0261 { 0262 FileTreeViewItem *foundItem = nullptr; 0263 for (int i = 0; i<item->childCount(); ++i) 0264 { 0265 FileTreeViewItem *child = static_cast<FileTreeViewItem *>(item->child(i)); 0266 if (child->text(0)==part) 0267 { 0268 foundItem = child; 0269 break; 0270 } 0271 } 0272 0273 if (foundItem==nullptr) 0274 { 0275 #ifdef DEBUG_MAPPING 0276 qCDebug(LIBFILETREE_LOG) << "didn't find" << part << "under" << item->url(); 0277 #endif 0278 return (nullptr); // no child with that name 0279 } 0280 0281 item = foundItem; 0282 } 0283 0284 #ifdef DEBUG_MAPPING 0285 qCDebug(LIBFILETREE_LOG) << "found" << item->url(); 0286 #endif 0287 return (item); 0288 } 0289 0290 void FileTreeBranch::itemRenamed(FileTreeViewItem *item) 0291 { 0292 QUrl u = m_itemMap.key(item); // find key for that item 0293 if (u.isEmpty()) return; // not in map, ignore 0294 m_itemMap.remove(u); // remove old from map 0295 m_itemMap[item->url()] = item; // save new item in map 0296 } 0297 0298 // No longer needed, itemsAdded signal passes parent URL 0299 //FileTreeViewItem *FileTreeBranch::parentFTVItem(const KFileItem &fi) 0300 //{ 0301 // if (fi.isNull()) return (nullptr); 0302 // 0303 // QUrl url = fi.url(); 0304 // //qCDebug(LIBFILETREE_LOG) << "for" << url; 0305 // url.setFileName(QString()); 0306 // return (findItemByUrl(url)); 0307 //} 0308 0309 FileTreeViewItem *FileTreeBranch::createTreeViewItem(FileTreeViewItem *parent, 0310 const KFileItem &fileItem) 0311 { 0312 FileTreeViewItem *tvi = nullptr; 0313 0314 if (parent != nullptr && !fileItem.isNull()) { 0315 tvi = new FileTreeViewItem(parent, fileItem, this); 0316 const QString p = fileItem.url().url(QUrl::PreferLocalFile|QUrl::StripTrailingSlash); 0317 m_itemMap[fileItem.url()] = tvi; 0318 #ifdef DEBUG_MAPPING 0319 qCDebug(LIBFILETREE_LOG) << "stored in map" << fileItem.url(); 0320 #endif 0321 } else { 0322 #ifdef DEBUG_MAPPING 0323 qCDebug(LIBFILETREE_LOG) << "no parent/fileitem for new item!"; 0324 #endif 0325 } 0326 return (tvi); 0327 } 0328 0329 void FileTreeBranch::slotItemsAdded(const QUrl &parent, const KFileItemList &items) 0330 { 0331 #ifdef DEBUG_LISTING 0332 qCDebug(LIBFILETREE_LOG) << "Adding" << items.count() << "items"; 0333 #endif // DEBUG_LISTING 0334 0335 FileTreeViewItem *parentItem = findItemByUrl(parent); 0336 if (parentItem == nullptr) { 0337 qCWarning(LIBFILETREE_LOG) << "parent item not found for" << parent; 0338 return; 0339 } 0340 0341 FileTreeViewItem *newItem; 0342 FileTreeViewItemList treeViewItList; // tree view items created 0343 for (KFileItemList::const_iterator it = items.constBegin(); 0344 it != items.constEnd(); ++it) { 0345 const KFileItem currItem = (*it); 0346 0347 /* Only create a new FileTreeViewItem if it does not yet exist */ 0348 if (findItemByUrl(currItem.url()) != nullptr) { 0349 continue; 0350 } 0351 0352 newItem = createTreeViewItem(parentItem, currItem); 0353 if (newItem == nullptr) { // should never happen now, 0354 // 'parent' checked above 0355 qCWarning(LIBFILETREE_LOG) << "failed to create item for" << currItem.url(); 0356 continue; 0357 } 0358 0359 // Cut off the file extension if requested, if it is not a directory 0360 if (!m_showExtensions && !currItem.isDir()) { 0361 QString name = currItem.text(); 0362 //int mPoint = name.lastIndexOf('.'); 0363 //if (mPoint>0) name = name.left(mPoint); 0364 0365 QMimeDatabase db; 0366 QString ext = db.suffixForFileName(name); 0367 if (!ext.isEmpty()) 0368 { 0369 name.chop(ext.length()+1); 0370 newItem->setText(0, name); 0371 } 0372 } 0373 0374 // TODO: is this useful (for local dirs) even in non-dirOnlyMode? 0375 // 0376 /* Now try to find out if there are children for dirs in the treeview */ 0377 /* This stats a directory on the local file system and checks the */ 0378 /* hardlink entry in the stat-buf. This works only for local directories. */ 0379 if (dirOnlyMode() && !m_recurseChildren && currItem.isLocalFile() && currItem.isDir()) { 0380 QUrl url = currItem.url(); 0381 QString filename = url.toLocalFile(); 0382 /* do the stat trick of Carsten. The problem is, that the hardlink 0383 * count only contains directory links. Thus, this method only seem 0384 * to work in dir-only mode */ 0385 #ifdef DEBUG_LISTING 0386 qCDebug(LIBFILETREE_LOG) << "Doing stat on" << filename; 0387 #endif // DEBUG_LISTING 0388 struct stat statBuf; 0389 if (stat(QFile::encodeName(filename).constData(), &statBuf) == 0) { 0390 int hardLinks = statBuf.st_nlink; /* Count of dirs */ 0391 #ifdef DEBUG_LISTING 0392 qCDebug(LIBFILETREE_LOG) << "stat succeeded, hardlinks: " << hardLinks; 0393 #endif // DEBUG_LISTING 0394 // If the link count is > 2, the directory likely has subdirs. If it's < 2 0395 // it's something weird like a mounted SMB share. In that case we don't know 0396 // if there are subdirs, thus show it as expandable. 0397 0398 if (hardLinks != 2) { 0399 newItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); 0400 } else { 0401 newItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator); 0402 } 0403 0404 if (hardLinks >= 2) { // "Normal" directory with subdirs 0405 hardLinks -= 2; 0406 #ifdef DEBUG_LISTING 0407 qCDebug(LIBFILETREE_LOG) << "Emitting directoryChildCount" << hardLinks << "for" << url; 0408 #endif // DEBUG_LISTING 0409 emit directoryChildCount(newItem, hardLinks); 0410 } 0411 } else { 0412 qCWarning(LIBFILETREE_LOG) << "stat of" << filename << "failed!"; 0413 } 0414 } 0415 0416 treeViewItList.append(newItem); 0417 } 0418 0419 if (treeViewItList.count() > 0) { 0420 emit newTreeViewItems(this, treeViewItList); 0421 } 0422 } 0423 0424 void FileTreeBranch::setChildRecurse(bool t) 0425 { 0426 m_recurseChildren = t; 0427 if (!t) { 0428 m_openChildrenURLs.clear(); 0429 } 0430 } 0431 0432 bool FileTreeBranch::childRecurse() 0433 { 0434 return (m_recurseChildren); 0435 } 0436 0437 void FileTreeBranch::setShowExtensions(bool visible) 0438 { 0439 m_showExtensions = visible; 0440 } 0441 0442 bool FileTreeBranch::showExtensions() const 0443 { 0444 return (m_showExtensions); 0445 } 0446 0447 /* 0448 * The signal that tells that a directory was deleted may arrive before the signal 0449 * for its children arrive. Thus, we must walk through the children of a dir and 0450 * remove them before removing the dir itself. 0451 */ 0452 0453 void FileTreeBranch::slotItemsDeleted(const KFileItemList &items) 0454 { 0455 for (KFileItemList::const_iterator it = items.constBegin(); 0456 it != items.constEnd(); ++it) { 0457 const KFileItem fi = (*it); 0458 itemDeleted(&fi); 0459 } 0460 } 0461 0462 void FileTreeBranch::itemDeleted(const KFileItem *fi) 0463 { 0464 if (fi->isNull()) { 0465 return; 0466 } 0467 #ifdef DEBUG_LISTING 0468 qCDebug(LIBFILETREE_LOG) << "for" << fi->url(); 0469 #endif // DEBUG_LISTING 0470 0471 FileTreeViewItem *ftvi = findItemByUrl(fi->url()); 0472 if (ftvi == nullptr) { 0473 #ifdef DEBUG_LISTING 0474 qCDebug(LIBFILETREE_LOG) << "no tree item!"; 0475 #endif // DEBUG_LISTING 0476 return; 0477 } 0478 0479 int nChildren = ftvi->childCount(); 0480 if (nChildren > 0) { 0481 #ifdef DEBUG_LISTING 0482 qCDebug(LIBFILETREE_LOG) << "child count" << nChildren; 0483 #endif // DEBUG_LISTING 0484 for (int i = 0; i < nChildren; ++i) { 0485 FileTreeViewItem *ch = static_cast<FileTreeViewItem *>(ftvi->child(i)); 0486 if (ch != nullptr) { 0487 itemDeleted(ch->fileItem()); 0488 } 0489 } 0490 } 0491 0492 QUrl u = fi->url(); 0493 if (u == m_lastFoundUrl) { 0494 m_lastFoundUrl = QUrl(); // invalidate last-found cache 0495 m_lastFoundItem = nullptr; 0496 } 0497 m_itemMap.remove(u); // remove from item map 0498 0499 delete ftvi; // finally remove view item 0500 } 0501 0502 void FileTreeBranch::slotListerCanceled(const QUrl &url) 0503 { 0504 #ifdef DEBUG_LISTING 0505 qCDebug(LIBFILETREE_LOG) << "lister cancelled for" << url; 0506 #endif // DEBUG_LISTING 0507 0508 // remove the URL from the children-to-recurse list 0509 m_openChildrenURLs.removeAll(url); 0510 0511 // stop animations, etc. 0512 FileTreeViewItem *item = findItemByUrl(url); 0513 if (item != nullptr) { 0514 emit populateFinished(item); 0515 } 0516 } 0517 0518 void FileTreeBranch::slotListerClear() 0519 { 0520 #ifdef DEBUG_LISTING 0521 qCDebug(LIBFILETREE_LOG); 0522 #endif // DEBUG_LISTING 0523 /* this slots needs to clear all listed items, but NOT the root item */ 0524 if (m_root != nullptr) { 0525 deleteChildrenOf(m_root); 0526 } 0527 } 0528 0529 void FileTreeBranch::slotListerClearUrl(const QUrl &url) 0530 { 0531 #ifdef DEBUG_LISTING 0532 qCDebug(LIBFILETREE_LOG) << "for" << url; 0533 #endif // DEBUG_LISTING 0534 FileTreeViewItem *ftvi = findItemByUrl(url); 0535 if (ftvi != nullptr) { 0536 deleteChildrenOf(ftvi); 0537 } 0538 } 0539 0540 void FileTreeBranch::deleteChildrenOf(QTreeWidgetItem *parent) 0541 { 0542 // for some strange reason, slotListerClearUrl() sometimes calls us 0543 // with a nullptr parent. 0544 if (parent == nullptr) { 0545 return; 0546 } 0547 0548 QList<QTreeWidgetItem *> childs = parent->takeChildren(); 0549 qDeleteAll(childs); 0550 } 0551 0552 void FileTreeBranch::slotRedirect(const QUrl &oldUrl, const QUrl &newUrl) 0553 { 0554 if (oldUrl.adjusted(QUrl::StripTrailingSlash) == 0555 m_startURL.adjusted(QUrl::StripTrailingSlash)) { 0556 m_startURL = newUrl; 0557 } 0558 } 0559 0560 void FileTreeBranch::slotListerCompleted(const QUrl &url) 0561 { 0562 #ifdef DEBUG_LISTING 0563 qCDebug(LIBFILETREE_LOG) << "lister completed for" << url; 0564 #endif // DEBUG_LISTING 0565 FileTreeViewItem *currParent = findItemByUrl(url); 0566 if (currParent == nullptr) { 0567 return; 0568 } 0569 0570 #ifdef DEBUG_LISTING 0571 qCDebug(LIBFILETREE_LOG) << "current parent" << currParent 0572 << "already listed?" << currParent->alreadyListed(); 0573 #endif // DEBUG_LISTING 0574 0575 emit populateFinished(currParent); 0576 emit directoryChildCount(currParent, currParent->childCount()); 0577 0578 /* This is a walk through the children of the last populated directory. 0579 * Here we start the dirlister on every child of the dir and wait for its 0580 * finish. When it has finished, we go to the next child. 0581 * This must be done for non local file systems in dirOnly- and Full-Mode 0582 * and for local file systems only in full mode, because the stat trick 0583 * (see addItem-Method) does only work for dirs, not for files in the directory. 0584 */ 0585 /* Set bit that the parent dir was listed completely */ 0586 currParent->setListed(true); 0587 0588 #ifdef DEBUG_LISTING 0589 qCDebug(LIBFILETREE_LOG) << "recurseChildren" << m_recurseChildren 0590 << "isLocalFile" << m_startURL.isLocalFile() 0591 << "dirOnlyMode" << dirOnlyMode(); 0592 #endif // DEBUG_LISTING 0593 0594 if (m_recurseChildren && (!m_startURL.isLocalFile() || !dirOnlyMode())) { 0595 bool wantRecurseUrl = false; 0596 /* look if the url is in the list for url to recurse */ 0597 for (const QUrl &u : qAsConst(m_openChildrenURLs)) { 0598 /* it is only interesting that the url _is_in_ the list. */ 0599 if (u.adjusted(QUrl::StripTrailingSlash) == url.adjusted(QUrl::StripTrailingSlash)) { 0600 wantRecurseUrl = true; 0601 break; 0602 } 0603 } 0604 0605 #ifdef DEBUG_LISTING 0606 qCDebug(LIBFILETREE_LOG) << "Recurse for" << url << wantRecurseUrl; 0607 #endif // DEBUG_LISTING 0608 int nChildren = 0; 0609 0610 if (wantRecurseUrl && currParent != nullptr) { 0611 /* now walk again through the tree and populate the children to get +-signs */ 0612 /* This is the starting point. The visible folder has finished, 0613 processing the children has not yet started */ 0614 nChildren = currParent->childCount(); 0615 if (nChildren == 0) { 0616 /* This happens if there is no child at all */ 0617 #ifdef DEBUG_LISTING 0618 qCDebug(LIBFILETREE_LOG) << "No children to recurse"; 0619 #endif // DEBUG_LISTING 0620 } 0621 0622 /* Since we have listed the children to recurse, we can remove the entry 0623 * in the list of the URLs to see the children. 0624 */ 0625 m_openChildrenURLs.removeAll(url); 0626 } 0627 0628 /* There are some children. We start a dirlister job on every child item 0629 * which is a directory to find out how much children are in the child 0630 * of the last opened dir. Skip non directory entries. 0631 */ 0632 0633 for (int i = 0; i < nChildren; ++i) { 0634 const FileTreeViewItem *ch = static_cast<FileTreeViewItem *>(currParent->child(i)); 0635 if (ch->isDir() && !ch->alreadyListed()) { 0636 const KFileItem *fi = ch->fileItem(); 0637 if (!fi->isNull() && fi->isReadable()) { 0638 QUrl recurseUrl = fi->url(); 0639 #ifdef DEBUG_LISTING 0640 qCDebug(LIBFILETREE_LOG) << "Starting to list" << recurseUrl; 0641 #endif // DEBUG_LISTING 0642 openUrl(recurseUrl, KCoreDirLister::Keep); 0643 } 0644 } 0645 } 0646 } 0647 #ifdef DEBUG_LISTING 0648 else { 0649 qCDebug(LIBFILETREE_LOG) << "no need to recurse"; 0650 } 0651 #endif // DEBUG_LISTING 0652 } 0653 0654 /* This slot is called when a tree view item is expanded in the GUI */ 0655 bool FileTreeBranch::populate(const QUrl &url, FileTreeViewItem *currItem) 0656 { 0657 bool ret = false; 0658 if (currItem == nullptr) { 0659 return (ret); 0660 } 0661 0662 #ifdef DEBUG_LISTING 0663 qCDebug(LIBFILETREE_LOG) << "populating" << url; 0664 #endif // DEBUG_LISTING 0665 0666 /* Add this url to the list of urls to recurse for children */ 0667 if (m_recurseChildren) { 0668 m_openChildrenURLs.append(url); 0669 #ifdef DEBUG_LISTING 0670 qCDebug(LIBFILETREE_LOG) << "Adding as open child"; 0671 #endif // DEBUG_LISTING 0672 } 0673 0674 if (!currItem->alreadyListed()) { 0675 #ifdef DEBUG_LISTING 0676 qCDebug(LIBFILETREE_LOG) << "Starting to list"; 0677 #endif // DEBUG_LISTING 0678 ret = openUrl(url, KCoreDirLister::Keep); // start the lister 0679 } else { 0680 #ifdef DEBUG_LISTING 0681 qCDebug(LIBFILETREE_LOG) << "Children already exist"; 0682 #endif // DEBUG_LISTING 0683 slotListerCompleted(url); 0684 ret = true; 0685 } 0686 0687 return (ret); 0688 }