File indexing completed on 2024-05-12 05:00:20

0001 /* This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
0003     SPDX-FileCopyrightText: 2002 Michael Brade <brade@kde.org>
0004     SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "dirtree_module.h"
0010 #include "dirtree_item.h"
0011 
0012 #include <kconfiggroup.h>
0013 #include <kio_version.h>
0014 #include <kprotocolmanager.h>
0015 #include <kdesktopfile.h>
0016 #include <kmessagebox.h>
0017 #include <kiconloader.h>
0018 #include <kdirlister.h>
0019 #include <KLocalizedString>
0020 
0021 KonqSidebarDirTreeModule::KonqSidebarDirTreeModule(KonqSidebarTree *parentTree, bool showHidden)
0022     : KonqSidebarTreeModule(parentTree, showHidden), m_dirLister(0L), m_topLevelItem(0L)
0023 {
0024     // SLOW! Get the KConfigGroup from the plugin.
0025     KConfig config("konqsidebartngrc");
0026     KConfigGroup generalGroup(&config, "General");
0027     m_showArchivesAsFolders = generalGroup.readEntry("ShowArchivesAsFolders", true);
0028 }
0029 
0030 KonqSidebarDirTreeModule::~KonqSidebarDirTreeModule()
0031 {
0032     // KDirLister may still emit canceled while being deleted.
0033     if (m_dirLister) {
0034         disconnect(m_dirLister, &KCoreDirLister::listingDirCanceled, this, &KonqSidebarDirTreeModule::slotListingStopped);
0035         delete m_dirLister;
0036     }
0037 }
0038 
0039 QList<QUrl> KonqSidebarDirTreeModule::selectedUrls()
0040 {
0041     QList<QUrl> lst;
0042     KonqSidebarDirTreeItem *selection = static_cast<KonqSidebarDirTreeItem *>(m_pTree->selectedItem());
0043     if (!selection) {
0044         kError() << "no selection!" << endl;
0045         return lst;
0046     }
0047     lst.append(selection->fileItem().url());
0048     return lst;
0049 }
0050 
0051 void KonqSidebarDirTreeModule::addTopLevelItem(KonqSidebarTreeTopLevelItem *item)
0052 {
0053     if (m_topLevelItem) { // We can handle only one at a time !
0054         kError() << "Impossible, we can have only one toplevel item !" << endl;
0055     }
0056 
0057     KDesktopFile cfg(item->path());
0058     KConfigGroup desktopGroup = cfg.desktopGroup();
0059 
0060     QUrl targetURL;
0061     targetURL.setPath(item->path());
0062 
0063     if (cfg.hasLinkType()) {
0064         targetURL = cfg.readUrl();
0065         // some services might want to make their URL configurable in kcontrol
0066         QString configured = desktopGroup.readPathEntry("X-KDE-ConfiguredURL", QString());
0067         if (!configured.isEmpty()) {
0068             QStringList list = configured.split(':');
0069             KConfig config(list[0]);
0070             KConfigGroup urlGroup(&config, list[1] != "noGroup" ? list[1] : "General");
0071             QString conf_url = urlGroup.readEntry(list[2], QString());
0072             if (!conf_url.isEmpty()) {
0073                 targetURL = conf_url;
0074             }
0075         }
0076     } else if (cfg.hasDeviceType()) {
0077         // Determine the mountpoint
0078         QString mp = desktopGroup.readPathEntry("MountPoint", QString());
0079         if (mp.isEmpty()) {
0080             return;
0081         }
0082 
0083         targetURL.setPath(mp);
0084     } else {
0085         return;
0086     }
0087 
0088     bool bListable = KProtocolManager::supportsListing(targetURL);
0089     //qCDebug(SIDEBAR_LOG) << targetURL.toDisplayString() << " listable : " << bListable;
0090 
0091     if (!bListable) {
0092         item->setExpandable(false);
0093         item->setListable(false);
0094     }
0095 
0096     item->setExternalURL(targetURL);
0097     addSubDir(item);
0098 
0099     m_topLevelItem = item;
0100 }
0101 
0102 void KonqSidebarDirTreeModule::openTopLevelItem(KonqSidebarTreeTopLevelItem *item)
0103 {
0104     if (!item->childCount() && item->isListable()) {
0105         openSubFolder(item);
0106     }
0107 }
0108 
0109 void KonqSidebarDirTreeModule::addSubDir(KonqSidebarTreeItem *item)
0110 {
0111     QString id = item->externalURL().adjusted(QUrl::StripTrailingSlash).toString();
0112     qCDebug(SIDEBAR_LOG) << this << id;
0113     m_dictSubDirs.insert(id, item);
0114 
0115     KonqSidebarDirTreeItem *ditem = dynamic_cast<KonqSidebarDirTreeItem *>(item);
0116     if (ditem) {
0117         m_ptrdictSubDirs.insert(ditem->fileItem(), item);
0118     }
0119 }
0120 
0121 // Remove <key, item> from dict, taking into account that there maybe
0122 // other items with the same key.
0123 static void remove(Q3Dict<KonqSidebarTreeItem> &dict, const QString &key, KonqSidebarTreeItem *item)
0124 {
0125     Q3PtrList<KonqSidebarTreeItem> *otherItems = 0;
0126     while (true) {
0127         KonqSidebarTreeItem *takeItem = dict.take(key);
0128         if (!takeItem || (takeItem == item)) {
0129             if (!otherItems) {
0130                 return;
0131             }
0132 
0133             // Insert the otherItems back in
0134             for (KonqSidebarTreeItem * otherItem; (otherItem = otherItems->take(0));) {
0135                 dict.insert(key, otherItem);
0136             }
0137             delete otherItems;
0138             return;
0139         }
0140         // Not the item we are looking for
0141         if (!otherItems) {
0142             otherItems = new Q3PtrList<KonqSidebarTreeItem>();
0143         }
0144 
0145         otherItems->prepend(takeItem);
0146     }
0147 }
0148 
0149 // Looks up key in dict and returns it in item, if there are multiple items
0150 // with the same key, additional items are returned in itemList which should
0151 // be deleted by the caller.
0152 static void lookupItems(Q3Dict<KonqSidebarTreeItem> &dict, const QString &key, KonqSidebarTreeItem *&item, Q3PtrList<KonqSidebarTreeItem> *&itemList)
0153 {
0154     itemList = 0;
0155     item = dict.take(key);
0156     if (!item) {
0157         return;
0158     }
0159 
0160     while (true) {
0161         KonqSidebarTreeItem *takeItem = dict.take(key);
0162         if (!takeItem) {
0163             //
0164             // Insert itemList back in
0165             if (itemList) {
0166                 for (KonqSidebarTreeItem *otherItem = itemList->first(); otherItem; otherItem = itemList->next()) {
0167                     dict.insert(key, otherItem);
0168                 }
0169             }
0170             dict.insert(key, item);
0171             return;
0172         }
0173         if (!itemList) {
0174             itemList = new Q3PtrList<KonqSidebarTreeItem>();
0175         }
0176 
0177         itemList->prepend(takeItem);
0178     }
0179 }
0180 
0181 // Remove <key, item> from dict, taking into account that there maybe
0182 // other items with the same key.
0183 static void remove(QHash<KFileItem, KonqSidebarTreeItem *> &dict, const KFileItem &key, KonqSidebarTreeItem *item)
0184 {
0185     Q3PtrList<KonqSidebarTreeItem> *otherItems = 0;
0186     while (true) {
0187         KonqSidebarTreeItem *takeItem = dict.take(key);
0188         if (!takeItem || (takeItem == item)) {
0189             if (!otherItems) {
0190                 return;
0191             }
0192 
0193             // Insert the otherItems back in
0194             for (KonqSidebarTreeItem * otherItem; (otherItem = otherItems->take(0));) {
0195                 dict.insert(key, otherItem);
0196             }
0197             delete otherItems;
0198             return;
0199         }
0200         // Not the item we are looking for
0201         if (!otherItems) {
0202             otherItems = new Q3PtrList<KonqSidebarTreeItem>();
0203         }
0204 
0205         otherItems->prepend(takeItem);
0206     }
0207 }
0208 
0209 // Looks up key in dict and returns it in item, if there are multiple items
0210 // with the same key, additional items are returned in itemList which should
0211 // be deleted by the caller.
0212 static void lookupItems(QHash<KFileItem, KonqSidebarTreeItem *> &dict, const KFileItem &key, KonqSidebarTreeItem *&item, Q3PtrList<KonqSidebarTreeItem> *&itemList)
0213 {
0214     itemList = 0;
0215     item = dict.take(key);
0216     if (!item) {
0217         return;
0218     }
0219 
0220     while (true) {
0221         KonqSidebarTreeItem *takeItem = dict.take(key);
0222         if (!takeItem) {
0223             //
0224             // Insert itemList back in
0225             if (itemList) {
0226                 for (KonqSidebarTreeItem *otherItem = itemList->first(); otherItem; otherItem = itemList->next()) {
0227                     dict.insert(key, otherItem);
0228                 }
0229             }
0230             dict.insert(key, item);
0231             return;
0232         }
0233         if (!itemList) {
0234             itemList = new Q3PtrList<KonqSidebarTreeItem>();
0235         }
0236 
0237         itemList->prepend(takeItem);
0238     }
0239 }
0240 
0241 void KonqSidebarDirTreeModule::removeSubDir(KonqSidebarTreeItem *item, bool childrenOnly)
0242 {
0243     qCDebug(SIDEBAR_LOG) << this << "item=" << item;
0244     if (item->firstChild()) {
0245         KonqSidebarTreeItem *it = static_cast<KonqSidebarTreeItem *>(item->firstChild());
0246         KonqSidebarTreeItem *next = 0L;
0247         while (it) {
0248             next = static_cast<KonqSidebarTreeItem *>(it->nextSibling());
0249             removeSubDir(it);
0250             delete it;
0251             it = next;
0252         }
0253     }
0254 
0255     if (!childrenOnly) {
0256         QString id = item->externalURL().adjusted(QUrl::StripTrailingSlash).toString();
0257         remove(m_dictSubDirs, id, item);
0258         while (!(item->alias.isEmpty())) {
0259             remove(m_dictSubDirs, item->alias.front(), item);
0260             item->alias.pop_front();
0261         }
0262 
0263         KonqSidebarDirTreeItem *ditem = dynamic_cast<KonqSidebarDirTreeItem *>(item);
0264         if (ditem) {
0265             remove(m_ptrdictSubDirs, ditem->fileItem(), item);
0266         }
0267     }
0268 }
0269 
0270 void KonqSidebarDirTreeModule::openSubFolder(KonqSidebarTreeItem *item)
0271 {
0272     qCDebug(SIDEBAR_LOG) << this << "openSubFolder(" << item->externalURL().prettyUrl() << ")";
0273 
0274     if (!m_dirLister) { // created on demand
0275         m_dirLister = new KDirLister();
0276         //m_dirLister->setDelayedMimeTypes( true ); // this was set, but it's wrong, without a KMimeTypeResolver...
0277         //m_dirLister->setDirOnlyMode( true );
0278 //  QStringList mimetypes;
0279 //  mimetypes<<QString("inode/directory");
0280 //  m_dirLister->setMimeFilter(mimetypes);
0281 
0282         connect(m_dirLister, SIGNAL(newItems(KFileItemList)),
0283                 this, SLOT(slotNewItems(KFileItemList)));
0284         connect(m_dirLister, SIGNAL(refreshItems(QList<QPair<KFileItem,KFileItem> >)),
0285                 this, SLOT(slotRefreshItems(QList<QPair<KFileItem,KFileItem> >)));
0286         connect(m_dirLister, SIGNAL(deleteItem(KFileItem)),
0287                 this, SLOT(slotDeleteItem(KFileItem)));
0288 
0289         connect(m_dirLister, &KCoreDirLister::listingDirCompleted, this, &KonqSidebarDirTreeModule::slotListingStopped);
0290         connect(m_dirLister, &KCoreDirLister::listingDirCanceled, this, &KonqSidebarDirTreeModule::slotListingStopped);
0291 
0292         connect(m_dirLister, SIGNAL(redirection(QUrl,QUrl)),
0293                 this, SLOT(slotRedirection(QUrl,QUrl)));
0294     }
0295 
0296     if (!item->isTopLevelItem() &&
0297             static_cast<KonqSidebarDirTreeItem *>(item)->hasStandardIcon()) {
0298         int size = KIconLoader::global()->currentSize(KIconLoader::Small);
0299         QPixmap pix = DesktopIcon("folder-open", size);
0300         m_pTree->startAnimation(item, "kde", 6, &pix);
0301     } else {
0302         m_pTree->startAnimation(item);
0303     }
0304 
0305     listDirectory(item);
0306 }
0307 
0308 void KonqSidebarDirTreeModule::listDirectory(KonqSidebarTreeItem *item)
0309 {
0310     // This causes a reparsing, but gets rid of the trailing slash
0311     QString strUrl = item->externalURL().adjusted(QUrl::StripTrailingSlash).toString();
0312     QUrl url(strUrl);
0313 
0314     Q3PtrList<KonqSidebarTreeItem> *itemList;
0315     KonqSidebarTreeItem *openItem;
0316     lookupItems(m_dictSubDirs, strUrl, openItem, itemList);
0317 
0318     while (openItem) {
0319         if (openItem->childCount()) {
0320             break;
0321         }
0322 
0323         openItem = itemList ? itemList->take(0) : 0;
0324     }
0325     delete itemList;
0326 
0327     if (openItem) {
0328         // We have this directory listed already, just copy the entries as we
0329         // can't use the dirlister, it would invalidate the old entries
0330         int size = KIconLoader::global()->currentSize(KIconLoader::Small);
0331         KonqSidebarTreeItem *parentItem = item;
0332         KonqSidebarDirTreeItem *oldItem = static_cast<KonqSidebarDirTreeItem *>(openItem->firstChild());
0333         while (oldItem) {
0334             const KFileItem fileItem = oldItem->fileItem();
0335             if (! fileItem.isDir()) {
0336                 if (!fileItem.url().isLocalFile()) {
0337                     continue;
0338                 }
0339                 KMimeType::Ptr ptr = fileItem.determineMimeType();
0340                 if (ptr && (ptr->is("inode/directory") || m_showArchivesAsFolders)
0341                         && ((!ptr->property("X-KDE-LocalProtocol").toString().isEmpty()))) {
0342                     qCDebug(SIDEBAR_LOG) << "Something not really a directory";
0343                 } else {
0344 //                kError() << "Item " << fileItem->url().prettyUrl() << " is not a directory!" << endl;
0345                     continue;
0346                 }
0347             }
0348 
0349             KonqSidebarDirTreeItem *dirTreeItem = new KonqSidebarDirTreeItem(parentItem, m_topLevelItem, fileItem);
0350             dirTreeItem->setPixmap(0, fileItem.pixmap(size));
0351             dirTreeItem->setText(0, KIO::decodeFileName(fileItem.name()));
0352 
0353             oldItem = static_cast<KonqSidebarDirTreeItem *>(oldItem->nextSibling());
0354         }
0355         m_pTree->stopAnimation(item);
0356 
0357         return;
0358     }
0359 
0360     m_dirLister->setShowingDotFiles(showHidden());
0361 
0362     if (tree()->isOpeningFirstChild()) {
0363         m_dirLister->setAutoErrorHandlingEnabled(false, 0);
0364     } else {
0365         m_dirLister->setAutoErrorHandlingEnabled(true, tree());
0366     }
0367 
0368     m_dirLister->openUrl(url, KDirLister::Keep);
0369 }
0370 
0371 void KonqSidebarDirTreeModule::slotNewItems(const KFileItemList &entries)
0372 {
0373     qCDebug(SIDEBAR_LOG) << this << entries.count();
0374 
0375     Q_ASSERT(entries.count());
0376     const KFileItem firstItem = entries.first();
0377 
0378     // Find parent item - it's the same for all the items
0379     QUrl dir(firstItem.url().adjusted(QUrl::StripTrailingSlash).toString());
0380     dir = dir.adjusted(QUrl::RemoveFilename);
0381     dir.setPath(dir.path() + "");
0382     qCDebug(SIDEBAR_LOG) << this << "dir=" << dir.adjusted(QUrl::StripTrailingSlash).toString();
0383 
0384     Q3PtrList<KonqSidebarTreeItem> *parentItemList;
0385     KonqSidebarTreeItem *parentItem;
0386     lookupItems(m_dictSubDirs, dir.adjusted(QUrl::StripTrailingSlash).toString(), parentItem, parentItemList);
0387 
0388     if (!parentItem) {   // hack for dnssd://domain/type/service listed in dnssd:/type/ dir
0389         dir.setHost(QString());
0390         lookupItems(m_dictSubDirs, dir.adjusted(QUrl::StripTrailingSlash).toString(), parentItem, parentItemList);
0391     }
0392 
0393     if (!parentItem) {
0394         KMessageBox::error(tree(), i18n("Cannot find parent item %1 in the tree. Internal error.", dir.adjusted(QUrl::StripTrailingSlash).toString()));
0395         return;
0396     }
0397 
0398     qCDebug(SIDEBAR_LOG) << "number of additional parent items:" << (parentItemList ? parentItemList->count() : 0);
0399     int size = KIconLoader::global()->currentSize(KIconLoader::Small);
0400     do {
0401         qCDebug(SIDEBAR_LOG) << "Parent Item URL:" << parentItem->externalURL();
0402         KFileItemList::const_iterator kit = entries.begin();
0403         const KFileItemList::const_iterator kend = entries.end();
0404         for (; kit != kend; ++kit) {
0405             const KFileItem fileItem = *kit;
0406 
0407             if (! fileItem.isDir()) {
0408                 if (!fileItem.url().isLocalFile()) {
0409                     continue;
0410                 }
0411                 KMimeType::Ptr ptr = fileItem.determineMimeType();
0412 
0413                 if (ptr && (ptr->is("inode/directory") || m_showArchivesAsFolders)
0414                         && ((!ptr->property("X-KDE-LocalProtocol").toString().isEmpty()))) {
0415                     qCDebug(SIDEBAR_LOG) << "Something really a directory";
0416                 } else {
0417                     //kError() << "Item " << fileItem->url().prettyUrl() << " is not a directory!" << endl;
0418                     continue;
0419                 }
0420             }
0421 
0422             KonqSidebarDirTreeItem *dirTreeItem = new KonqSidebarDirTreeItem(parentItem, m_topLevelItem, fileItem);
0423             dirTreeItem->setPixmap(0, fileItem.pixmap(size));
0424             dirTreeItem->setText(0, KIO::decodeFileName(fileItem.name()));
0425         }
0426 
0427     } while ((parentItem = parentItemList ? parentItemList->take(0) : 0));
0428     delete parentItemList;
0429 }
0430 
0431 void KonqSidebarDirTreeModule::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &entries)
0432 {
0433     int size = KIconLoader::global()->currentSize(KIconLoader::Small);
0434 
0435     qCDebug(SIDEBAR_LOG) << "# of items to refresh:" << entries.count();
0436 
0437     for (int i = 0; i < entries.count(); ++i) {
0438         const KFileItem fileItem(entries.at(i).second);
0439         const KFileItem oldFileItem(entries.at(i).first);
0440 
0441         Q3PtrList<KonqSidebarTreeItem> *itemList;
0442         KonqSidebarTreeItem *item;
0443         lookupItems(m_ptrdictSubDirs, oldFileItem, item, itemList);
0444 
0445         if (!item) {
0446             kWarning(1201) << "can't find old entry for " << oldFileItem.url().adjusted(QUrl::StripTrailingSlash).toString();
0447             continue;
0448         }
0449 
0450         do {
0451             if (item->isTopLevelItem()) { // we only have dirs and one toplevel item in the dict
0452                 kWarning(1201) << "entry for " << oldFileItem.url().adjusted(QUrl::StripTrailingSlash).toString() << "matches against toplevel.";
0453                 break;
0454             }
0455 
0456             KonqSidebarDirTreeItem *dirTreeItem = static_cast<KonqSidebarDirTreeItem *>(item);
0457             // Item renamed ?
0458             if (dirTreeItem->id != fileItem.url().adjusted(QUrl::StripTrailingSlash).toString()) {
0459                 qCDebug(SIDEBAR_LOG) << "renaming" << oldFileItem << "->" << fileItem;
0460                 // We need to update the URL in m_dictSubDirs, and to get rid of the child items, so remove and add.
0461                 // Then remove + delete
0462                 removeSubDir(dirTreeItem, true /*children only*/);
0463                 remove(m_dictSubDirs, dirTreeItem->id, dirTreeItem);
0464                 remove(m_ptrdictSubDirs, oldFileItem, dirTreeItem);
0465 
0466                 dirTreeItem->reset(); // Reset id
0467                 dirTreeItem->setPixmap(0, fileItem.pixmap(size));
0468                 dirTreeItem->setText(0, KIO::decodeFileName(fileItem.name()));
0469 
0470                 // Make sure the item doesn't get inserted twice!
0471                 // dirTreeItem->id points to the new name
0472                 remove(m_dictSubDirs, dirTreeItem->id, dirTreeItem);
0473                 remove(m_ptrdictSubDirs, fileItem, dirTreeItem);
0474                 m_dictSubDirs.insert(dirTreeItem->id, dirTreeItem);
0475                 m_ptrdictSubDirs.insert(fileItem, dirTreeItem);
0476             } else {
0477                 dirTreeItem->setPixmap(0, fileItem.pixmap(size));
0478                 dirTreeItem->setText(0, KIO::decodeFileName(fileItem.name()));
0479             }
0480 
0481         } while ((item = itemList ? itemList->take(0) : 0));
0482         delete itemList;
0483     }
0484 }
0485 
0486 void KonqSidebarDirTreeModule::slotDeleteItem(const KFileItem &fileItem)
0487 {
0488     qCDebug(SIDEBAR_LOG) << fileItem.url().adjusted(QUrl::StripTrailingSlash).toString();
0489 
0490     // All items are in m_ptrdictSubDirs, so look it up fast
0491     Q3PtrList<KonqSidebarTreeItem> *itemList;
0492     KonqSidebarTreeItem *item;
0493     lookupItems(m_dictSubDirs, fileItem.url().adjusted(QUrl::StripTrailingSlash).toString(), item, itemList);
0494     while (item) {
0495         removeSubDir(item);
0496         delete item;
0497 
0498         item = itemList ? itemList->take(0) : 0;
0499     }
0500     delete itemList;
0501 }
0502 
0503 void KonqSidebarDirTreeModule::slotRedirection(const QUrl &oldUrl, const QUrl &newUrl)
0504 {
0505     qCDebug(SIDEBAR_LOG) << newUrl;
0506 
0507     QString oldUrlStr = oldUrl.adjusted(QUrl::StripTrailingSlash).toString();
0508     QString newUrlStr = newUrl.adjusted(QUrl::StripTrailingSlash).toString();
0509 
0510     Q3PtrList<KonqSidebarTreeItem> *itemList;
0511     KonqSidebarTreeItem *item;
0512     lookupItems(m_dictSubDirs, oldUrlStr, item, itemList);
0513 
0514     if (!item) {
0515         kWarning(1201) << "NOT FOUND   oldUrl=" << oldUrlStr;
0516         return;
0517     }
0518 
0519     do {
0520         if (item->alias.contains(newUrlStr)) {
0521             continue;
0522         }
0523         qCDebug(SIDEBAR_LOG) << "Redirectiong element";
0524         // We need to update the URL in m_dictSubDirs
0525         m_dictSubDirs.insert(newUrlStr, item);
0526         item->alias << newUrlStr;
0527 
0528         qCDebug(SIDEBAR_LOG) << "Updating url of " << item << " to " << newUrlStr;
0529 
0530     } while ((item = itemList ? itemList->take(0) : 0));
0531     delete itemList;
0532 }
0533 
0534 void KonqSidebarDirTreeModule::slotListingStopped(const QUrl &url)
0535 {
0536     //qCDebug(SIDEBAR_LOG) << url;
0537 
0538     Q3PtrList<KonqSidebarTreeItem> *itemList;
0539     KonqSidebarTreeItem *item;
0540     lookupItems(m_dictSubDirs, url.adjusted(QUrl::StripTrailingSlash).toString(), item, itemList);
0541 
0542     while (item) {
0543         if (item->childCount() == 0) {
0544             item->setExpandable(false);
0545             item->repaint();
0546         }
0547         m_pTree->stopAnimation(item);
0548 
0549         item = itemList ? itemList->take(0) : 0;
0550     }
0551     delete itemList;
0552 
0553     //qCDebug(SIDEBAR_LOG) << "m_selectAfterOpening " << m_selectAfterOpening.prettyUrl();
0554     if (!m_selectAfterOpening.isEmpty() && url.isParentOf(m_selectAfterOpening)) {
0555         QUrl theURL(m_selectAfterOpening);
0556         m_selectAfterOpening = QUrl();
0557         followURL(theURL);
0558     }
0559 }
0560 
0561 void KonqSidebarDirTreeModule::followURL(const QUrl &url)
0562 {
0563     // Check if we already know this URL
0564     KonqSidebarTreeItem *item = m_dictSubDirs[ url.adjusted(QUrl::StripTrailingSlash).toString() ];
0565     if (item) { // found it  -> ensure visible, select, return.
0566         m_pTree->ensureItemVisible(item);
0567         m_pTree->setSelected(item, true);
0568         return;
0569     }
0570 
0571     QUrl uParent(url);
0572     KonqSidebarTreeItem *parentItem = 0L;
0573     // Go up to the first known parent
0574     do {
0575         uParent = uParent.upUrl();
0576         parentItem = m_dictSubDirs[ uParent.adjusted(QUrl::StripTrailingSlash).toString() ];
0577     } while (!parentItem && !uParent.path().isEmpty() && uParent.path() != "/");
0578 
0579     // Not found !?!
0580     if (!parentItem) {
0581         qCDebug(SIDEBAR_LOG) << "No parent found for url " << url.toDisplayString();
0582         return;
0583     }
0584     qCDebug(SIDEBAR_LOG) << "Found parent " << uParent.toDisplayString();
0585 
0586     // That's the parent directory we found. Open if not open...
0587     if (!parentItem->isOpen()) {
0588         parentItem->setOpen(true);
0589         if (parentItem->childCount() && m_dictSubDirs[ url.adjusted(QUrl::StripTrailingSlash).toString() ]) {
0590             // Immediate opening, if the dir was already listed
0591             followURL(url);   // equivalent to a goto-beginning-of-method
0592         } else {
0593             m_selectAfterOpening = url;
0594             //qCDebug(SIDEBAR_LOG) << "m_selectAfterOpening=" << m_selectAfterOpening.url();
0595         }
0596     }
0597 }
0598 
0599 extern "C"
0600 {
0601     KDE_EXPORT KonqSidebarTreeModule *create_konq_sidebartree_dirtree(KonqSidebarTree *par, const bool showHidden)
0602     {
0603         return new KonqSidebarDirTreeModule(par, showHidden);
0604     }
0605 }
0606