1 /* This file is part of the KDE project
2 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
3 SPDX-FileCopyrightText: 2002 Michael Brade <brade@kde.org>
4 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7 */
8
9 #include "dirtree_module.h"
10 #include "dirtree_item.h"
11
12 #include <kconfiggroup.h>
13 #include <kio_version.h>
14 #include <kprotocolmanager.h>
15 #include <kdesktopfile.h>
16 #include <kmessagebox.h>
17 #include <kiconloader.h>
18 #include <kdirlister.h>
19 #include <KLocalizedString>
20
KonqSidebarDirTreeModule(KonqSidebarTree * parentTree,bool showHidden)21 KonqSidebarDirTreeModule::KonqSidebarDirTreeModule(KonqSidebarTree *parentTree, bool showHidden)
22 : KonqSidebarTreeModule(parentTree, showHidden), m_dirLister(0L), m_topLevelItem(0L)
23 {
24 // SLOW! Get the KConfigGroup from the plugin.
25 KConfig config("konqsidebartngrc");
26 KConfigGroup generalGroup(&config, "General");
27 m_showArchivesAsFolders = generalGroup.readEntry("ShowArchivesAsFolders", true);
28 }
29
~KonqSidebarDirTreeModule()30 KonqSidebarDirTreeModule::~KonqSidebarDirTreeModule()
31 {
32 // KDirLister may still emit canceled while being deleted.
33 if (m_dirLister) {
34 #if KIO_VERSION < QT_VERSION_CHECK(5, 79, 0)
35 disconnect(m_dirLister, SIGNAL(canceled(QUrl)),
36 this, SLOT(slotListingStopped(QUrl)));
37 #else
38 disconnect(m_dirLister, &KCoreDirLister::listingDirCanceled, this, &KonqSidebarDirTreeModule::slotListingStopped);
39 #endif
40 delete m_dirLister;
41 }
42 }
43
selectedUrls()44 QList<QUrl> KonqSidebarDirTreeModule::selectedUrls()
45 {
46 QList<QUrl> lst;
47 KonqSidebarDirTreeItem *selection = static_cast<KonqSidebarDirTreeItem *>(m_pTree->selectedItem());
48 if (!selection) {
49 kError() << "no selection!" << endl;
50 return lst;
51 }
52 lst.append(selection->fileItem().url());
53 return lst;
54 }
55
addTopLevelItem(KonqSidebarTreeTopLevelItem * item)56 void KonqSidebarDirTreeModule::addTopLevelItem(KonqSidebarTreeTopLevelItem *item)
57 {
58 if (m_topLevelItem) { // We can handle only one at a time !
59 kError() << "Impossible, we can have only one toplevel item !" << endl;
60 }
61
62 KDesktopFile cfg(item->path());
63 KConfigGroup desktopGroup = cfg.desktopGroup();
64
65 QUrl targetURL;
66 targetURL.setPath(item->path());
67
68 if (cfg.hasLinkType()) {
69 targetURL = cfg.readUrl();
70 // some services might want to make their URL configurable in kcontrol
71 QString configured = desktopGroup.readPathEntry("X-KDE-ConfiguredURL", QString());
72 if (!configured.isEmpty()) {
73 QStringList list = configured.split(':');
74 KConfig config(list[0]);
75 KConfigGroup urlGroup(&config, list[1] != "noGroup" ? list[1] : "General");
76 QString conf_url = urlGroup.readEntry(list[2], QString());
77 if (!conf_url.isEmpty()) {
78 targetURL = conf_url;
79 }
80 }
81 } else if (cfg.hasDeviceType()) {
82 // Determine the mountpoint
83 QString mp = desktopGroup.readPathEntry("MountPoint", QString());
84 if (mp.isEmpty()) {
85 return;
86 }
87
88 targetURL.setPath(mp);
89 } else {
90 return;
91 }
92
93 bool bListable = KProtocolManager::supportsListing(targetURL);
94 //qCDebug(SIDEBAR_LOG) << targetURL.toDisplayString() << " listable : " << bListable;
95
96 if (!bListable) {
97 item->setExpandable(false);
98 item->setListable(false);
99 }
100
101 item->setExternalURL(targetURL);
102 addSubDir(item);
103
104 m_topLevelItem = item;
105 }
106
openTopLevelItem(KonqSidebarTreeTopLevelItem * item)107 void KonqSidebarDirTreeModule::openTopLevelItem(KonqSidebarTreeTopLevelItem *item)
108 {
109 if (!item->childCount() && item->isListable()) {
110 openSubFolder(item);
111 }
112 }
113
addSubDir(KonqSidebarTreeItem * item)114 void KonqSidebarDirTreeModule::addSubDir(KonqSidebarTreeItem *item)
115 {
116 QString id = item->externalURL().adjusted(QUrl::StripTrailingSlash).toString();
117 qCDebug(SIDEBAR_LOG) << this << id;
118 m_dictSubDirs.insert(id, item);
119
120 KonqSidebarDirTreeItem *ditem = dynamic_cast<KonqSidebarDirTreeItem *>(item);
121 if (ditem) {
122 m_ptrdictSubDirs.insert(ditem->fileItem(), item);
123 }
124 }
125
126 // Remove <key, item> from dict, taking into account that there maybe
127 // other items with the same key.
remove(Q3Dict<KonqSidebarTreeItem> & dict,const QString & key,KonqSidebarTreeItem * item)128 static void remove(Q3Dict<KonqSidebarTreeItem> &dict, const QString &key, KonqSidebarTreeItem *item)
129 {
130 Q3PtrList<KonqSidebarTreeItem> *otherItems = 0;
131 while (true) {
132 KonqSidebarTreeItem *takeItem = dict.take(key);
133 if (!takeItem || (takeItem == item)) {
134 if (!otherItems) {
135 return;
136 }
137
138 // Insert the otherItems back in
139 for (KonqSidebarTreeItem * otherItem; (otherItem = otherItems->take(0));) {
140 dict.insert(key, otherItem);
141 }
142 delete otherItems;
143 return;
144 }
145 // Not the item we are looking for
146 if (!otherItems) {
147 otherItems = new Q3PtrList<KonqSidebarTreeItem>();
148 }
149
150 otherItems->prepend(takeItem);
151 }
152 }
153
154 // Looks up key in dict and returns it in item, if there are multiple items
155 // with the same key, additional items are returned in itemList which should
156 // be deleted by the caller.
lookupItems(Q3Dict<KonqSidebarTreeItem> & dict,const QString & key,KonqSidebarTreeItem * & item,Q3PtrList<KonqSidebarTreeItem> * & itemList)157 static void lookupItems(Q3Dict<KonqSidebarTreeItem> &dict, const QString &key, KonqSidebarTreeItem *&item, Q3PtrList<KonqSidebarTreeItem> *&itemList)
158 {
159 itemList = 0;
160 item = dict.take(key);
161 if (!item) {
162 return;
163 }
164
165 while (true) {
166 KonqSidebarTreeItem *takeItem = dict.take(key);
167 if (!takeItem) {
168 //
169 // Insert itemList back in
170 if (itemList) {
171 for (KonqSidebarTreeItem *otherItem = itemList->first(); otherItem; otherItem = itemList->next()) {
172 dict.insert(key, otherItem);
173 }
174 }
175 dict.insert(key, item);
176 return;
177 }
178 if (!itemList) {
179 itemList = new Q3PtrList<KonqSidebarTreeItem>();
180 }
181
182 itemList->prepend(takeItem);
183 }
184 }
185
186 // Remove <key, item> from dict, taking into account that there maybe
187 // other items with the same key.
remove(QHash<KFileItem,KonqSidebarTreeItem * > & dict,const KFileItem & key,KonqSidebarTreeItem * item)188 static void remove(QHash<KFileItem, KonqSidebarTreeItem *> &dict, const KFileItem &key, KonqSidebarTreeItem *item)
189 {
190 Q3PtrList<KonqSidebarTreeItem> *otherItems = 0;
191 while (true) {
192 KonqSidebarTreeItem *takeItem = dict.take(key);
193 if (!takeItem || (takeItem == item)) {
194 if (!otherItems) {
195 return;
196 }
197
198 // Insert the otherItems back in
199 for (KonqSidebarTreeItem * otherItem; (otherItem = otherItems->take(0));) {
200 dict.insert(key, otherItem);
201 }
202 delete otherItems;
203 return;
204 }
205 // Not the item we are looking for
206 if (!otherItems) {
207 otherItems = new Q3PtrList<KonqSidebarTreeItem>();
208 }
209
210 otherItems->prepend(takeItem);
211 }
212 }
213
214 // Looks up key in dict and returns it in item, if there are multiple items
215 // with the same key, additional items are returned in itemList which should
216 // be deleted by the caller.
lookupItems(QHash<KFileItem,KonqSidebarTreeItem * > & dict,const KFileItem & key,KonqSidebarTreeItem * & item,Q3PtrList<KonqSidebarTreeItem> * & itemList)217 static void lookupItems(QHash<KFileItem, KonqSidebarTreeItem *> &dict, const KFileItem &key, KonqSidebarTreeItem *&item, Q3PtrList<KonqSidebarTreeItem> *&itemList)
218 {
219 itemList = 0;
220 item = dict.take(key);
221 if (!item) {
222 return;
223 }
224
225 while (true) {
226 KonqSidebarTreeItem *takeItem = dict.take(key);
227 if (!takeItem) {
228 //
229 // Insert itemList back in
230 if (itemList) {
231 for (KonqSidebarTreeItem *otherItem = itemList->first(); otherItem; otherItem = itemList->next()) {
232 dict.insert(key, otherItem);
233 }
234 }
235 dict.insert(key, item);
236 return;
237 }
238 if (!itemList) {
239 itemList = new Q3PtrList<KonqSidebarTreeItem>();
240 }
241
242 itemList->prepend(takeItem);
243 }
244 }
245
removeSubDir(KonqSidebarTreeItem * item,bool childrenOnly)246 void KonqSidebarDirTreeModule::removeSubDir(KonqSidebarTreeItem *item, bool childrenOnly)
247 {
248 qCDebug(SIDEBAR_LOG) << this << "item=" << item;
249 if (item->firstChild()) {
250 KonqSidebarTreeItem *it = static_cast<KonqSidebarTreeItem *>(item->firstChild());
251 KonqSidebarTreeItem *next = 0L;
252 while (it) {
253 next = static_cast<KonqSidebarTreeItem *>(it->nextSibling());
254 removeSubDir(it);
255 delete it;
256 it = next;
257 }
258 }
259
260 if (!childrenOnly) {
261 QString id = item->externalURL().adjusted(QUrl::StripTrailingSlash).toString();
262 remove(m_dictSubDirs, id, item);
263 while (!(item->alias.isEmpty())) {
264 remove(m_dictSubDirs, item->alias.front(), item);
265 item->alias.pop_front();
266 }
267
268 KonqSidebarDirTreeItem *ditem = dynamic_cast<KonqSidebarDirTreeItem *>(item);
269 if (ditem) {
270 remove(m_ptrdictSubDirs, ditem->fileItem(), item);
271 }
272 }
273 }
274
openSubFolder(KonqSidebarTreeItem * item)275 void KonqSidebarDirTreeModule::openSubFolder(KonqSidebarTreeItem *item)
276 {
277 qCDebug(SIDEBAR_LOG) << this << "openSubFolder(" << item->externalURL().prettyUrl() << ")";
278
279 if (!m_dirLister) { // created on demand
280 m_dirLister = new KDirLister();
281 //m_dirLister->setDelayedMimeTypes( true ); // this was set, but it's wrong, without a KMimeTypeResolver...
282 //m_dirLister->setDirOnlyMode( true );
283 // QStringList mimetypes;
284 // mimetypes<<QString("inode/directory");
285 // m_dirLister->setMimeFilter(mimetypes);
286
287 connect(m_dirLister, SIGNAL(newItems(KFileItemList)),
288 this, SLOT(slotNewItems(KFileItemList)));
289 connect(m_dirLister, SIGNAL(refreshItems(QList<QPair<KFileItem,KFileItem> >)),
290 this, SLOT(slotRefreshItems(QList<QPair<KFileItem,KFileItem> >)));
291 connect(m_dirLister, SIGNAL(deleteItem(KFileItem)),
292 this, SLOT(slotDeleteItem(KFileItem)));
293
294 #if KIO_VERSION < QT_VERSION_CHECK(5, 79, 0)
295 connect(m_dirLister, SIGNAL(completed(QUrl)),
296 this, SLOT(slotListingStopped(QUrl)));
297 connect(m_dirLister, SIGNAL(canceled(QUrl)),
298 this, SLOT(slotListingStopped(QUrl)));
299 #else
300 connect(m_dirLister, &KCoreDirLister::listingDirCompleted, this, &KonqSidebarDirTreeModule::slotListingStopped);
301 connect(m_dirLister, &KCoreDirLister::listingDirCanceled, this, &KonqSidebarDirTreeModule::slotListingStopped);
302 #endif
303
304 connect(m_dirLister, SIGNAL(redirection(QUrl,QUrl)),
305 this, SLOT(slotRedirection(QUrl,QUrl)));
306 }
307
308 if (!item->isTopLevelItem() &&
309 static_cast<KonqSidebarDirTreeItem *>(item)->hasStandardIcon()) {
310 int size = KIconLoader::global()->currentSize(KIconLoader::Small);
311 QPixmap pix = DesktopIcon("folder-open", size);
312 m_pTree->startAnimation(item, "kde", 6, &pix);
313 } else {
314 m_pTree->startAnimation(item);
315 }
316
317 listDirectory(item);
318 }
319
listDirectory(KonqSidebarTreeItem * item)320 void KonqSidebarDirTreeModule::listDirectory(KonqSidebarTreeItem *item)
321 {
322 // This causes a reparsing, but gets rid of the trailing slash
323 QString strUrl = item->externalURL().adjusted(QUrl::StripTrailingSlash).toString();
324 QUrl url(strUrl);
325
326 Q3PtrList<KonqSidebarTreeItem> *itemList;
327 KonqSidebarTreeItem *openItem;
328 lookupItems(m_dictSubDirs, strUrl, openItem, itemList);
329
330 while (openItem) {
331 if (openItem->childCount()) {
332 break;
333 }
334
335 openItem = itemList ? itemList->take(0) : 0;
336 }
337 delete itemList;
338
339 if (openItem) {
340 // We have this directory listed already, just copy the entries as we
341 // can't use the dirlister, it would invalidate the old entries
342 int size = KIconLoader::global()->currentSize(KIconLoader::Small);
343 KonqSidebarTreeItem *parentItem = item;
344 KonqSidebarDirTreeItem *oldItem = static_cast<KonqSidebarDirTreeItem *>(openItem->firstChild());
345 while (oldItem) {
346 const KFileItem fileItem = oldItem->fileItem();
347 if (! fileItem.isDir()) {
348 if (!fileItem.url().isLocalFile()) {
349 continue;
350 }
351 KMimeType::Ptr ptr = fileItem.determineMimeType();
352 if (ptr && (ptr->is("inode/directory") || m_showArchivesAsFolders)
353 && ((!ptr->property("X-KDE-LocalProtocol").toString().isEmpty()))) {
354 qCDebug(SIDEBAR_LOG) << "Something not really a directory";
355 } else {
356 // kError() << "Item " << fileItem->url().prettyUrl() << " is not a directory!" << endl;
357 continue;
358 }
359 }
360
361 KonqSidebarDirTreeItem *dirTreeItem = new KonqSidebarDirTreeItem(parentItem, m_topLevelItem, fileItem);
362 dirTreeItem->setPixmap(0, fileItem.pixmap(size));
363 dirTreeItem->setText(0, KIO::decodeFileName(fileItem.name()));
364
365 oldItem = static_cast<KonqSidebarDirTreeItem *>(oldItem->nextSibling());
366 }
367 m_pTree->stopAnimation(item);
368
369 return;
370 }
371
372 m_dirLister->setShowingDotFiles(showHidden());
373
374 if (tree()->isOpeningFirstChild()) {
375 m_dirLister->setAutoErrorHandlingEnabled(false, 0);
376 } else {
377 m_dirLister->setAutoErrorHandlingEnabled(true, tree());
378 }
379
380 m_dirLister->openUrl(url, KDirLister::Keep);
381 }
382
slotNewItems(const KFileItemList & entries)383 void KonqSidebarDirTreeModule::slotNewItems(const KFileItemList &entries)
384 {
385 qCDebug(SIDEBAR_LOG) << this << entries.count();
386
387 Q_ASSERT(entries.count());
388 const KFileItem firstItem = entries.first();
389
390 // Find parent item - it's the same for all the items
391 QUrl dir(firstItem.url().adjusted(QUrl::StripTrailingSlash).toString());
392 dir = dir.adjusted(QUrl::RemoveFilename);
393 dir.setPath(dir.path() + "");
394 qCDebug(SIDEBAR_LOG) << this << "dir=" << dir.adjusted(QUrl::StripTrailingSlash).toString();
395
396 Q3PtrList<KonqSidebarTreeItem> *parentItemList;
397 KonqSidebarTreeItem *parentItem;
398 lookupItems(m_dictSubDirs, dir.adjusted(QUrl::StripTrailingSlash).toString(), parentItem, parentItemList);
399
400 if (!parentItem) { // hack for dnssd://domain/type/service listed in dnssd:/type/ dir
401 dir.setHost(QString());
402 lookupItems(m_dictSubDirs, dir.adjusted(QUrl::StripTrailingSlash).toString(), parentItem, parentItemList);
403 }
404
405 if (!parentItem) {
406 KMessageBox::error(tree(), i18n("Cannot find parent item %1 in the tree. Internal error.", dir.adjusted(QUrl::StripTrailingSlash).toString()));
407 return;
408 }
409
410 qCDebug(SIDEBAR_LOG) << "number of additional parent items:" << (parentItemList ? parentItemList->count() : 0);
411 int size = KIconLoader::global()->currentSize(KIconLoader::Small);
412 do {
413 qCDebug(SIDEBAR_LOG) << "Parent Item URL:" << parentItem->externalURL();
414 KFileItemList::const_iterator kit = entries.begin();
415 const KFileItemList::const_iterator kend = entries.end();
416 for (; kit != kend; ++kit) {
417 const KFileItem fileItem = *kit;
418
419 if (! fileItem.isDir()) {
420 if (!fileItem.url().isLocalFile()) {
421 continue;
422 }
423 KMimeType::Ptr ptr = fileItem.determineMimeType();
424
425 if (ptr && (ptr->is("inode/directory") || m_showArchivesAsFolders)
426 && ((!ptr->property("X-KDE-LocalProtocol").toString().isEmpty()))) {
427 qCDebug(SIDEBAR_LOG) << "Something really a directory";
428 } else {
429 //kError() << "Item " << fileItem->url().prettyUrl() << " is not a directory!" << endl;
430 continue;
431 }
432 }
433
434 KonqSidebarDirTreeItem *dirTreeItem = new KonqSidebarDirTreeItem(parentItem, m_topLevelItem, fileItem);
435 dirTreeItem->setPixmap(0, fileItem.pixmap(size));
436 dirTreeItem->setText(0, KIO::decodeFileName(fileItem.name()));
437 }
438
439 } while ((parentItem = parentItemList ? parentItemList->take(0) : 0));
440 delete parentItemList;
441 }
442
slotRefreshItems(const QList<QPair<KFileItem,KFileItem>> & entries)443 void KonqSidebarDirTreeModule::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &entries)
444 {
445 int size = KIconLoader::global()->currentSize(KIconLoader::Small);
446
447 qCDebug(SIDEBAR_LOG) << "# of items to refresh:" << entries.count();
448
449 for (int i = 0; i < entries.count(); ++i) {
450 const KFileItem fileItem(entries.at(i).second);
451 const KFileItem oldFileItem(entries.at(i).first);
452
453 Q3PtrList<KonqSidebarTreeItem> *itemList;
454 KonqSidebarTreeItem *item;
455 lookupItems(m_ptrdictSubDirs, oldFileItem, item, itemList);
456
457 if (!item) {
458 kWarning(1201) << "can't find old entry for " << oldFileItem.url().adjusted(QUrl::StripTrailingSlash).toString();
459 continue;
460 }
461
462 do {
463 if (item->isTopLevelItem()) { // we only have dirs and one toplevel item in the dict
464 kWarning(1201) << "entry for " << oldFileItem.url().adjusted(QUrl::StripTrailingSlash).toString() << "matches against toplevel.";
465 break;
466 }
467
468 KonqSidebarDirTreeItem *dirTreeItem = static_cast<KonqSidebarDirTreeItem *>(item);
469 // Item renamed ?
470 if (dirTreeItem->id != fileItem.url().adjusted(QUrl::StripTrailingSlash).toString()) {
471 qCDebug(SIDEBAR_LOG) << "renaming" << oldFileItem << "->" << fileItem;
472 // We need to update the URL in m_dictSubDirs, and to get rid of the child items, so remove and add.
473 // Then remove + delete
474 removeSubDir(dirTreeItem, true /*children only*/);
475 remove(m_dictSubDirs, dirTreeItem->id, dirTreeItem);
476 remove(m_ptrdictSubDirs, oldFileItem, dirTreeItem);
477
478 dirTreeItem->reset(); // Reset id
479 dirTreeItem->setPixmap(0, fileItem.pixmap(size));
480 dirTreeItem->setText(0, KIO::decodeFileName(fileItem.name()));
481
482 // Make sure the item doesn't get inserted twice!
483 // dirTreeItem->id points to the new name
484 remove(m_dictSubDirs, dirTreeItem->id, dirTreeItem);
485 remove(m_ptrdictSubDirs, fileItem, dirTreeItem);
486 m_dictSubDirs.insert(dirTreeItem->id, dirTreeItem);
487 m_ptrdictSubDirs.insert(fileItem, dirTreeItem);
488 } else {
489 dirTreeItem->setPixmap(0, fileItem.pixmap(size));
490 dirTreeItem->setText(0, KIO::decodeFileName(fileItem.name()));
491 }
492
493 } while ((item = itemList ? itemList->take(0) : 0));
494 delete itemList;
495 }
496 }
497
slotDeleteItem(const KFileItem & fileItem)498 void KonqSidebarDirTreeModule::slotDeleteItem(const KFileItem &fileItem)
499 {
500 qCDebug(SIDEBAR_LOG) << fileItem.url().adjusted(QUrl::StripTrailingSlash).toString();
501
502 // All items are in m_ptrdictSubDirs, so look it up fast
503 Q3PtrList<KonqSidebarTreeItem> *itemList;
504 KonqSidebarTreeItem *item;
505 lookupItems(m_dictSubDirs, fileItem.url().adjusted(QUrl::StripTrailingSlash).toString(), item, itemList);
506 while (item) {
507 removeSubDir(item);
508 delete item;
509
510 item = itemList ? itemList->take(0) : 0;
511 }
512 delete itemList;
513 }
514
slotRedirection(const QUrl & oldUrl,const QUrl & newUrl)515 void KonqSidebarDirTreeModule::slotRedirection(const QUrl &oldUrl, const QUrl &newUrl)
516 {
517 qCDebug(SIDEBAR_LOG) << newUrl;
518
519 QString oldUrlStr = oldUrl.adjusted(QUrl::StripTrailingSlash).toString();
520 QString newUrlStr = newUrl.adjusted(QUrl::StripTrailingSlash).toString();
521
522 Q3PtrList<KonqSidebarTreeItem> *itemList;
523 KonqSidebarTreeItem *item;
524 lookupItems(m_dictSubDirs, oldUrlStr, item, itemList);
525
526 if (!item) {
527 kWarning(1201) << "NOT FOUND oldUrl=" << oldUrlStr;
528 return;
529 }
530
531 do {
532 if (item->alias.contains(newUrlStr)) {
533 continue;
534 }
535 qCDebug(SIDEBAR_LOG) << "Redirectiong element";
536 // We need to update the URL in m_dictSubDirs
537 m_dictSubDirs.insert(newUrlStr, item);
538 item->alias << newUrlStr;
539
540 qCDebug(SIDEBAR_LOG) << "Updating url of " << item << " to " << newUrlStr;
541
542 } while ((item = itemList ? itemList->take(0) : 0));
543 delete itemList;
544 }
545
slotListingStopped(const QUrl & url)546 void KonqSidebarDirTreeModule::slotListingStopped(const QUrl &url)
547 {
548 //qCDebug(SIDEBAR_LOG) << url;
549
550 Q3PtrList<KonqSidebarTreeItem> *itemList;
551 KonqSidebarTreeItem *item;
552 lookupItems(m_dictSubDirs, url.adjusted(QUrl::StripTrailingSlash).toString(), item, itemList);
553
554 while (item) {
555 if (item->childCount() == 0) {
556 item->setExpandable(false);
557 item->repaint();
558 }
559 m_pTree->stopAnimation(item);
560
561 item = itemList ? itemList->take(0) : 0;
562 }
563 delete itemList;
564
565 //qCDebug(SIDEBAR_LOG) << "m_selectAfterOpening " << m_selectAfterOpening.prettyUrl();
566 if (!m_selectAfterOpening.isEmpty() && url.isParentOf(m_selectAfterOpening)) {
567 QUrl theURL(m_selectAfterOpening);
568 m_selectAfterOpening = QUrl();
569 followURL(theURL);
570 }
571 }
572
followURL(const QUrl & url)573 void KonqSidebarDirTreeModule::followURL(const QUrl &url)
574 {
575 // Check if we already know this URL
576 KonqSidebarTreeItem *item = m_dictSubDirs[ url.adjusted(QUrl::StripTrailingSlash).toString() ];
577 if (item) { // found it -> ensure visible, select, return.
578 m_pTree->ensureItemVisible(item);
579 m_pTree->setSelected(item, true);
580 return;
581 }
582
583 QUrl uParent(url);
584 KonqSidebarTreeItem *parentItem = 0L;
585 // Go up to the first known parent
586 do {
587 uParent = uParent.upUrl();
588 parentItem = m_dictSubDirs[ uParent.adjusted(QUrl::StripTrailingSlash).toString() ];
589 } while (!parentItem && !uParent.path().isEmpty() && uParent.path() != "/");
590
591 // Not found !?!
592 if (!parentItem) {
593 qCDebug(SIDEBAR_LOG) << "No parent found for url " << url.toDisplayString();
594 return;
595 }
596 qCDebug(SIDEBAR_LOG) << "Found parent " << uParent.toDisplayString();
597
598 // That's the parent directory we found. Open if not open...
599 if (!parentItem->isOpen()) {
600 parentItem->setOpen(true);
601 if (parentItem->childCount() && m_dictSubDirs[ url.adjusted(QUrl::StripTrailingSlash).toString() ]) {
602 // Immediate opening, if the dir was already listed
603 followURL(url); // equivalent to a goto-beginning-of-method
604 } else {
605 m_selectAfterOpening = url;
606 //qCDebug(SIDEBAR_LOG) << "m_selectAfterOpening=" << m_selectAfterOpening.url();
607 }
608 }
609 }
610
611 extern "C"
612 {
create_konq_sidebartree_dirtree(KonqSidebarTree * par,const bool showHidden)613 KDE_EXPORT KonqSidebarTreeModule *create_konq_sidebartree_dirtree(KonqSidebarTree *par, const bool showHidden)
614 {
615 return new KonqSidebarDirTreeModule(par, showHidden);
616 }
617 }
618
619