File indexing completed on 2024-04-28 04:58:27

0001 /* This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
0003     SPDX-FileCopyrightText: 2000 Carsten Pfeiffer <pfeiffer@kde.org>
0004     SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "konq_sidebartree.h"
0010 #include "konq_sidebartreemodule.h"
0011 #include "konqsidebar_oldtreemodule.h"
0012 
0013 #include <QClipboard>
0014 #include <QCursor>
0015 #include <QDir>
0016 #include <Qt3Support/Q3Header>
0017 #include <QMenu>
0018 #include <QTimer>
0019 #include <QApplication>
0020 
0021 #include <QAction>
0022 #include <kactioncollection.h>
0023 #include <kdirnotify.h>
0024 #include <kdesktopfile.h>
0025 #include <kglobalsettings.h>
0026 #include <klibrary.h>
0027 #include <QIcon>
0028 #include <kiconloader.h>
0029 #include <kinputdialog.h>
0030 #include <kio/netaccess.h>
0031 #include <KLocalizedString>
0032 #include <kmimetype.h>
0033 #include <kshell.h>
0034 #include <kpropertiesdialog.h>
0035 #include <kprotocolinfo.h>
0036 #include <kstandarddirs.h>
0037 #include <k3urldrag.h>
0038 
0039 #include <stdlib.h>
0040 #include <assert.h>
0041 #include <QStandardPaths>
0042 
0043 static const int autoOpenTimeout = 750;
0044 
0045 getModule KonqSidebarTree::getPluginFactory(const QString &name)
0046 {
0047     if (!pluginFactories.contains(name)) {
0048         QString libName    = pluginInfo[name];
0049         KLibrary lib(libName);
0050         if (lib.load()) {
0051             // get the create_ function
0052             QString factory = "create_" + libName;
0053             KLibrary::void_function_ptr create    = lib.resolveFunction(QFile::encodeName(factory));
0054             if (create) {
0055                 getModule func = (getModule)create;
0056                 pluginFactories.insert(name, func);
0057                 qCDebug(SIDEBAR_LOG) << "Added a module";
0058             } else {
0059                 kWarning() << "No create function found in" << libName;
0060             }
0061         } else {
0062             kWarning() << "Module " << libName << " can't be loaded!";
0063         }
0064     }
0065 
0066     return pluginFactories[name];
0067 }
0068 
0069 void KonqSidebarTree::loadModuleFactories()
0070 {
0071     pluginFactories.clear();
0072     pluginInfo.clear();
0073     KStandardDirs *dirs = KGlobal::dirs();
0074     const QStringList list = dirs->findAllResources("data", "konqsidebartng/dirtree/*.desktop", KStandardDirs::NoDuplicates);
0075 
0076     for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
0077         KConfig _ksc(*it, KConfig::SimpleConfig);
0078         KConfigGroup ksc(&_ksc, "Desktop Entry");
0079         QString name    = ksc.readEntry("X-KDE-TreeModule");
0080         QString libName = ksc.readEntry("X-KDE-TreeModule-Lib");
0081         if ((name.isEmpty()) || (libName.isEmpty())) {
0082             kWarning() << "Bad Configuration file for a dirtree module " << *it;
0083             continue;
0084         }
0085 
0086         //Register the library info.
0087         pluginInfo[name] = libName;
0088     }
0089 }
0090 
0091 class KonqSidebarTree_Internal
0092 {
0093 public:
0094     DropAcceptType m_dropMode;
0095     QStringList m_dropFormats;
0096 };
0097 
0098 KonqSidebarTree::KonqSidebarTree(KonqSidebarOldTreeModule *parent, QWidget *parentWidget, ModuleType moduleType, const QString &path)
0099     : K3ListView(parentWidget),
0100       m_currentTopLevelItem(0),
0101       m_scrollingLocked(false),
0102       m_collection(0)
0103 {
0104     d = new KonqSidebarTree_Internal;
0105     d->m_dropMode = SidebarTreeMode;
0106 
0107     loadModuleFactories();
0108 
0109     setAcceptDrops(true);
0110     viewport()->setAcceptDrops(true);
0111     installEventFilter(this);
0112     m_lstModules.setAutoDelete(true);
0113 
0114     setSelectionMode(Q3ListView::Single);
0115     setDragEnabled(true);
0116 
0117     m_sidebarModule = parent;
0118 
0119     m_animationTimer = new QTimer(this);
0120     connect(m_animationTimer, SIGNAL(timeout()),
0121             this, SLOT(slotAnimation()));
0122 
0123     m_currentBeforeDropItem = 0;
0124     m_dropItem = 0;
0125     m_bOpeningFirstChild = false;
0126 
0127     addColumn(QString());
0128     header()->hide();
0129     setTreeStepSize(15);
0130 
0131     m_autoOpenTimer = new QTimer(this);
0132     connect(m_autoOpenTimer, SIGNAL(timeout()),
0133             this, SLOT(slotAutoOpenFolder()));
0134 
0135     connect(this, SIGNAL(doubleClicked(Q3ListViewItem*)),
0136             this, SLOT(slotDoubleClicked(Q3ListViewItem*)));
0137     connect(this, SIGNAL(mouseButtonPressed(int,Q3ListViewItem*,QPoint,int)),
0138             this, SLOT(slotMouseButtonPressed(int,Q3ListViewItem*,QPoint,int)));
0139     connect(this, SIGNAL(mouseButtonClicked(int,Q3ListViewItem*,QPoint,int)),
0140             this, SLOT(slotMouseButtonClicked(int,Q3ListViewItem*,QPoint,int)));
0141     connect(this, SIGNAL(returnPressed(Q3ListViewItem*)),
0142             this, SLOT(slotDoubleClicked(Q3ListViewItem*)));
0143     connect(this, SIGNAL(selectionChanged()),
0144             this, SLOT(slotSelectionChanged()));
0145     connect(qApp->clipboard(), SIGNAL(dataChanged()),
0146             this, SLOT(slotSelectionChanged())); // so that "paste" can be updated
0147 
0148     connect(this, SIGNAL(itemRenamed(Q3ListViewItem*,QString,int)),
0149             this, SLOT(slotItemRenamed(Q3ListViewItem*,QString,int)));
0150 
0151     if (moduleType == VIRT_Folder) {
0152         m_dirtreeDir.dir.setPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "konqsidebartng/virtual_folders/" + path + '/');
0153         m_dirtreeDir.relDir = path;
0154     } else {
0155         m_dirtreeDir.dir.setPath(path);
0156     }
0157     qCDebug(SIDEBAR_LOG) << m_dirtreeDir.dir.path();
0158     m_dirtreeDir.type = moduleType;
0159     // Initial parsing
0160     rescanConfiguration();
0161 
0162     if (firstChild()) {
0163         m_bOpeningFirstChild = true;
0164         firstChild()->setOpen(true);
0165         m_bOpeningFirstChild = false;
0166     }
0167 
0168     OrgKdeKDirNotifyInterface *kdirnotify = new OrgKdeKDirNotifyInterface(QString(), QString(), QDBusConnection::sessionBus());
0169     kdirnotify->setParent(this);
0170     connect(kdirnotify, SIGNAL(FilesAdded(QString)), SLOT(slotFilesAdded(QString)));
0171     connect(kdirnotify, SIGNAL(FilesChanged(QStringList)), SLOT(slotFilesChanged(QStringList)));
0172     connect(kdirnotify, SIGNAL(FilesRemoved(QStringList)), SLOT(slotFilesRemoved(QStringList)));
0173 
0174     m_collection = new KActionCollection(this);
0175     m_collection->addAssociatedWidget(this);
0176     m_collection->setObjectName(QLatin1String("bookmark actions"));
0177     QAction *action = new QAction(QIcon::fromTheme("folder-new"), i18n("&Create New Folder..."), this);
0178     m_collection->addAction("create_folder", action);
0179     connect(action, SIGNAL(triggered(bool)), SLOT(slotCreateFolder()));
0180 
0181     action = new QAction(QIcon::fromTheme("edit-delete"), i18n("Delete Folder"), this);
0182     m_collection->addAction("delete", action);
0183     connect(action, SIGNAL(triggered(bool)), SLOT(slotDelete()));
0184 
0185     action = new QAction(QIcon::fromTheme("user-trash"), i18n("Move to Trash"), this);
0186     m_collection->addAction("trash", action);
0187     connect(action, SIGNAL(triggered(bool)), SLOT(slotTrash()));
0188 
0189     action = new QAction(i18n("Rename"), this);
0190     action->setIcon(QIcon::fromTheme("edit-rename"));
0191     m_collection->addAction("rename", action);
0192     connect(action, SIGNAL(triggered(bool)), SLOT(slotRename()));
0193 
0194     action = new QAction(QIcon::fromTheme("edit-delete"), i18n("Delete Link"), this);
0195     m_collection->addAction("delete_link", action);
0196     connect(action, SIGNAL(triggered(bool)), SLOT(slotDelete()));
0197 
0198     action = new QAction(QIcon::fromTheme("document-properties"), i18n("Properties"), this);
0199     m_collection->addAction("item_properties", action);
0200     connect(action, SIGNAL(triggered(bool)), SLOT(slotProperties()));
0201 
0202     action = new QAction(QIcon::fromTheme("window-new"), i18n("Open in New Window"), this);
0203     m_collection->addAction("open_window", action);
0204     connect(action, SIGNAL(triggered(bool)), SLOT(slotOpenNewWindow()));
0205 
0206     action = new QAction(QIcon::fromTheme("tab-new"), i18n("Open in New Tab"), this);
0207     m_collection->addAction("open_tab", action);
0208     connect(action, SIGNAL(triggered(bool)), SLOT(slotOpenTab()));
0209 
0210     action = new QAction(QIcon::fromTheme("edit-copy"), i18n("Copy Link Address"), this);
0211     m_collection->addAction("copy_location", action);
0212     connect(action, SIGNAL(triggered(bool)), SLOT(slotCopyLocation()));
0213 }
0214 
0215 KonqSidebarTree::~KonqSidebarTree()
0216 {
0217     clearTree();
0218 
0219     delete d;
0220 }
0221 
0222 void KonqSidebarTree::itemDestructed(KonqSidebarTreeItem *item)
0223 {
0224     stopAnimation(item);
0225 
0226     if (item == m_currentBeforeDropItem) {
0227         m_currentBeforeDropItem = 0;
0228     }
0229 }
0230 
0231 void KonqSidebarTree::setDropFormats(const QStringList &formats)
0232 {
0233     d->m_dropFormats = formats;
0234 }
0235 
0236 void KonqSidebarTree::clearTree()
0237 {
0238     m_lstModules.clear();
0239     m_topLevelItems.clear();
0240     m_mapCurrentOpeningFolders.clear();
0241     m_currentBeforeDropItem = 0;
0242     clear();
0243 
0244     if (m_dirtreeDir.type == VIRT_Folder) {
0245         setRootIsDecorated(true);
0246     } else {
0247         setRootIsDecorated(false);
0248     }
0249 }
0250 
0251 void KonqSidebarTree::followURL(const QUrl &url)
0252 {
0253     // Maybe we're there already ?
0254     KonqSidebarTreeItem *selection = static_cast<KonqSidebarTreeItem *>(selectedItem());
0255     if (selection && selection->externalURL().equals(url, QUrl::CompareWithoutTrailingSlash)) {
0256         ensureItemVisible(selection);
0257         return;
0258     }
0259 
0260     qCDebug(SIDEBAR_LOG) << url.url();
0261     Q3PtrListIterator<KonqSidebarTreeTopLevelItem> topItem(m_topLevelItems);
0262     for (; topItem.current(); ++topItem) {
0263         if (topItem.current()->externalURL().isParentOf(url)) {
0264             topItem.current()->module()->followURL(url);
0265             return; // done
0266         }
0267     }
0268     qCDebug(SIDEBAR_LOG) << "Not found";
0269 }
0270 
0271 void KonqSidebarTree::contentsDragEnterEvent(QDragEnterEvent *ev)
0272 {
0273     m_dropItem = 0;
0274     m_currentBeforeDropItem = selectedItem();
0275     // Save the available formats
0276     m_lstDropFormats.clear();
0277     for (int i = 0; ev->format(i); i++)
0278         if (*(ev->format(i))) {
0279             m_lstDropFormats.append(ev->format(i));
0280         }
0281     K3ListView::contentsDragEnterEvent(ev);
0282 }
0283 
0284 void KonqSidebarTree::contentsDragMoveEvent(QDragMoveEvent *e)
0285 {
0286     Q3ListViewItem *item = itemAt(contentsToViewport(e->pos()));
0287 
0288     // Accept drops on the background, if URLs
0289     if (!item && m_lstDropFormats.contains("text/uri-list")) {
0290         m_dropItem = 0;
0291         e->acceptProposedAction();
0292         if (selectedItem()) {
0293             setSelected(selectedItem(), false);    // no item selected
0294         }
0295         return;
0296     }
0297 
0298     if (item && static_cast<KonqSidebarTreeItem *>(item)->acceptsDrops(m_lstDropFormats)) {
0299         d->m_dropMode = SidebarTreeMode;
0300 
0301         if (!item->isSelectable()) {
0302             m_dropItem = 0;
0303             m_autoOpenTimer->stop();
0304             e->ignore();
0305             return;
0306         }
0307 
0308         e->acceptProposedAction();
0309 
0310         setSelected(item, true);
0311 
0312         if (item != m_dropItem) {
0313             m_autoOpenTimer->stop();
0314             m_dropItem = item;
0315             m_autoOpenTimer->start(autoOpenTimeout);
0316         }
0317     } else {
0318         d->m_dropMode = K3ListViewMode;
0319         K3ListView::contentsDragMoveEvent(e);
0320     }
0321 }
0322 
0323 void KonqSidebarTree::contentsDragLeaveEvent(QDragLeaveEvent *ev)
0324 {
0325     // Restore the current item to what it was before the dragging (#17070)
0326     if (m_currentBeforeDropItem) {
0327         setSelected(m_currentBeforeDropItem, true);
0328     } else {
0329         setSelected(m_dropItem, false);    // no item selected
0330     }
0331     m_currentBeforeDropItem = 0;
0332     m_dropItem = 0;
0333     m_lstDropFormats.clear();
0334 
0335     if (d->m_dropMode == K3ListViewMode) {
0336         K3ListView::contentsDragLeaveEvent(ev);
0337     }
0338 }
0339 
0340 void KonqSidebarTree::contentsDropEvent(QDropEvent *ev)
0341 {
0342     if (d->m_dropMode == SidebarTreeMode) {
0343         m_autoOpenTimer->stop();
0344 
0345         if (!selectedItem()) {
0346             //        KonqOperations::doDrop( 0L, m_dirtreeDir.dir, ev, this );
0347             QList<QUrl> urls;
0348             if (K3URLDrag::decode(ev, urls)) {
0349                 for (QList<QUrl>::ConstIterator it = urls.constBegin();
0350                         it != urls.constEnd(); ++it) {
0351                     addUrl(0, *it);
0352                 }
0353             }
0354         } else {
0355             KonqSidebarTreeItem *selection = static_cast<KonqSidebarTreeItem *>(selectedItem());
0356             selection->drop(ev);
0357         }
0358     } else {
0359         K3ListView::contentsDropEvent(ev);
0360     }
0361 }
0362 
0363 static QString findUniqueFilename(const QString &path, const QString &filename)
0364 {
0365     QString tempFilename = filename;
0366     if (tempFilename.endsWith(".desktop")) {
0367         tempFilename.truncate(tempFilename.length() - 8);
0368     }
0369 
0370     QString name = tempFilename;
0371     int n = 2;
0372     while (QFile::exists(path + tempFilename + ".desktop")) {
0373         tempFilename = QString("%2_%1").arg(n++).arg(name);
0374     }
0375     return path + tempFilename + ".desktop";
0376 }
0377 
0378 void KonqSidebarTree::addUrl(KonqSidebarTreeTopLevelItem *item, const QUrl &url)
0379 {
0380     QString path;
0381     if (item) {
0382         path = item->path();
0383     } else {
0384         path = m_dirtreeDir.dir.path();
0385     }
0386 
0387     QUrl destUrl;
0388 
0389     if (url.isLocalFile() && url.fileName().endsWith(".desktop")) {
0390         QString filename = findUniqueFilename(path, url.fileName());
0391         destUrl.setPath(filename);
0392         KIO::NetAccess::file_copy(url, destUrl, this);
0393     } else {
0394         QString name = url.host();
0395         if (name.isEmpty()) {
0396             name = url.fileName();
0397         }
0398         QString filename = findUniqueFilename(path, name);
0399         destUrl.setPath(filename);
0400 
0401         KDesktopFile desktopFile(filename);
0402         KConfigGroup cfg = desktopFile.desktopGroup();
0403         cfg.writeEntry("Encoding", "UTF-8");
0404         cfg.writeEntry("Type", "Link");
0405         cfg.writeEntry("URL", url.url());
0406         QString icon = "folder";
0407         if (!url.isLocalFile()) {
0408             icon = KMimeType::favIconForUrl(url);
0409         }
0410         if (icon.isEmpty()) {
0411             icon = KProtocolInfo::icon(url.scheme());
0412         }
0413         cfg.writeEntry("Icon", icon);
0414         cfg.writeEntry("Name", name);
0415         cfg.writeEntry("Open", false);
0416         cfg.sync();
0417     }
0418 
0419     destUrl.setPath(destUrl.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path());
0420     OrgKdeKDirNotifyInterface::emitFilesAdded(destUrl.url());
0421 
0422     if (item) {
0423         item->setOpen(true);
0424     }
0425 }
0426 
0427 bool KonqSidebarTree::acceptDrag(QDropEvent *e) const
0428 {
0429     // for K3ListViewMode...
0430     for (int i = 0; e->format(i); i++)
0431         if (d->m_dropFormats.contains(e->format(i))) {
0432             return true;
0433         }
0434     return false;
0435 }
0436 
0437 Q3DragObject *KonqSidebarTree::dragObject()
0438 {
0439     KonqSidebarTreeItem *item = static_cast<KonqSidebarTreeItem *>(selectedItem());
0440     if (!item) {
0441         return 0;
0442     }
0443 
0444     QMimeData *mimeData = new QMimeData;
0445     if (item->populateMimeData(mimeData, false)) {
0446         QDrag *drag = new QDrag(viewport());
0447         drag->setMimeData(mimeData);
0448         const QPixmap *pix = item->pixmap(0);
0449         if (pix && drag->pixmap().isNull()) {
0450             drag->setPixmap(*pix);
0451         }
0452     } else {
0453         delete mimeData;
0454         mimeData = 0;
0455     }
0456 
0457 #ifdef __GNUC__
0458 #warning TODO port to QDrag (only possible once porting away from Q3ListView?)
0459 #endif
0460     return 0;
0461     //return drag;
0462 }
0463 
0464 void KonqSidebarTree::leaveEvent(QEvent *e)
0465 {
0466     K3ListView::leaveEvent(e);
0467 //    emitStatusBarText( QString() );
0468 }
0469 
0470 void KonqSidebarTree::slotDoubleClicked(Q3ListViewItem *item)
0471 {
0472     //qCDebug(SIDEBAR_LOG) << item;
0473     if (!item) {
0474         return;
0475     }
0476 
0477     if (!static_cast<KonqSidebarTreeItem *>(item)->isClickable()) {
0478         return;
0479     }
0480 
0481     slotExecuted(item);
0482     item->setOpen(!item->isOpen());
0483 }
0484 
0485 void KonqSidebarTree::slotExecuted(Q3ListViewItem *item)
0486 {
0487     qCDebug(SIDEBAR_LOG) << item;
0488     if (!item) {
0489         return;
0490     }
0491 
0492     if (!static_cast<KonqSidebarTreeItem *>(item)->isClickable()) {
0493         return;
0494     }
0495 
0496     KonqSidebarTreeItem *dItem = static_cast<KonqSidebarTreeItem *>(item);
0497 
0498     KParts::OpenUrlArguments args;
0499     args.setMimeType(dItem->externalMimeType());
0500     BrowserArguments browserArgs;
0501     browserArgs.trustedSource = true; // is this needed?
0502     QUrl externalURL = dItem->externalURL();
0503     if (!externalURL.isEmpty()) {
0504         openUrlRequest(externalURL, args, browserArgs);
0505     }
0506 }
0507 
0508 void KonqSidebarTree::slotMouseButtonPressed(int _button, Q3ListViewItem *_item, const QPoint &, int col)
0509 {
0510     KonqSidebarTreeItem *item = static_cast<KonqSidebarTreeItem *>(_item);
0511     if (_button == Qt::RightButton) {
0512         if (item && col < 2) {
0513             item->setSelected(true);
0514             item->rightButtonPressed();
0515         }
0516     }
0517 }
0518 
0519 void KonqSidebarTree::slotMouseButtonClicked(int _button, Q3ListViewItem *_item, const QPoint &, int col)
0520 {
0521     KonqSidebarTreeItem *item = static_cast<KonqSidebarTreeItem *>(_item);
0522     if (_item && col < 2) {
0523         switch (_button) {
0524         case Qt::LeftButton:
0525             slotExecuted(item);
0526             break;
0527         case Qt::MiddleButton:
0528             item->middleButtonClicked();
0529             break;
0530         }
0531     }
0532 }
0533 
0534 void KonqSidebarTree::slotAutoOpenFolder()
0535 {
0536     m_autoOpenTimer->stop();
0537 
0538     if (!m_dropItem || m_dropItem->isOpen()) {
0539         return;
0540     }
0541 
0542     m_dropItem->setOpen(true);
0543     m_dropItem->repaint();
0544 }
0545 
0546 void KonqSidebarTree::rescanConfiguration()
0547 {
0548     qCDebug(SIDEBAR_LOG);
0549     m_autoOpenTimer->stop();
0550     clearTree();
0551     if (m_dirtreeDir.type == VIRT_Folder) {
0552         qCDebug(SIDEBAR_LOG) << "-->scanDir";
0553         scanDir(0, m_dirtreeDir.dir.path(), true);
0554 
0555     } else {
0556         qCDebug(SIDEBAR_LOG) << "-->loadTopLevel";
0557         loadTopLevelItem(0, m_dirtreeDir.dir.path());
0558     }
0559 }
0560 
0561 void KonqSidebarTree::slotSelectionChanged()
0562 {
0563     if (!m_dropItem) { // don't do this while the dragmove thing
0564         KonqSidebarTreeItem *item = static_cast<KonqSidebarTreeItem *>(selectedItem());
0565         if (item) {
0566             item->itemSelected();
0567         }
0568         /* else   -- doesn't seem to happen
0569            {} */
0570     }
0571 }
0572 
0573 void KonqSidebarTree::slotFilesAdded(const QString &dir)
0574 {
0575     QUrl urlDir(dir);
0576     qCDebug(SIDEBAR_LOG) << dir;
0577     if (m_dirtreeDir.dir.isParentOf(urlDir))
0578         // We use a timer in case of DBus re-entrance..
0579     {
0580         QTimer::singleShot(0, this, SLOT(rescanConfiguration()));
0581     }
0582 }
0583 
0584 void KonqSidebarTree::slotFilesRemoved(const QStringList &urls)
0585 {
0586     //qCDebug(SIDEBAR_LOG) << "KonqSidebarTree::slotFilesRemoved " << urls.count();
0587     for (QStringList::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it) {
0588         QUrl u(*it);
0589         //qCDebug(SIDEBAR_LOG) <<  "KonqSidebarTree::slotFilesRemoved " << u;
0590         if (m_dirtreeDir.dir.isParentOf(u)) {
0591             QTimer::singleShot(0, this, SLOT(rescanConfiguration()));
0592             qCDebug(SIDEBAR_LOG) << "done";
0593             return;
0594         }
0595     }
0596 }
0597 
0598 void KonqSidebarTree::slotFilesChanged(const QStringList &urls)
0599 {
0600     //qCDebug(SIDEBAR_LOG) << "KonqSidebarTree::slotFilesChanged";
0601     // not same signal, but same implementation
0602     slotFilesRemoved(urls);
0603 }
0604 
0605 void KonqSidebarTree::scanDir(KonqSidebarTreeItem *parent, const QString &path, bool isRoot)
0606 {
0607     QDir dir(path);
0608 
0609     if (!dir.isReadable()) {
0610         return;
0611     }
0612 
0613     qCDebug(SIDEBAR_LOG) << "scanDir" << path;
0614 
0615     QStringList entries = dir.entryList(QDir::Files);
0616     QStringList dirEntries = dir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot);
0617 
0618     if (isRoot) {
0619         bool copyConfig = (entries.isEmpty() && dirEntries.isEmpty());
0620         if (!copyConfig) {
0621             // Check version number
0622             // Version 1 was the dirtree of KDE 2.0.x (no versioning at that time, so default)
0623             // Version 2 includes the history
0624             // Version 3 includes the bookmarks
0625             // Version 4 includes lan.desktop and floppy.desktop, Alex
0626             // Version 5 includes the audiocd browser
0627             // Version 6 includes the printmanager and lan browser
0628             const int currentVersion = 6;
0629             QString key = QString::fromLatin1("X-KDE-DirTreeVersionNumber");
0630             KConfig versionCfg(path + "/.directory", KConfig::SimpleConfig);
0631             KConfigGroup generalGroup(&versionCfg, "General");
0632             int versionNumber = generalGroup.readEntry(key, 1);
0633             qCDebug(SIDEBAR_LOG) << "found version " << versionNumber;
0634             if (versionNumber < currentVersion) {
0635                 generalGroup.writeEntry(key, currentVersion);
0636                 versionCfg.sync();
0637                 copyConfig = true;
0638             }
0639         }
0640         if (copyConfig) {
0641             // We will copy over the configuration for the dirtree, from the global directory
0642             const QStringList dirtree_dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "konqsidebartng/virtual_folders/" + m_dirtreeDir.relDir + '/');
0643 
0644 //            QString dirtree_dir = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "konqsidebartng/virtual_folders/"+m_dirtreeDir.relDir+"/").last();  // most global
0645 //            qCDebug(SIDEBAR_LOG) << "dirtree_dir=" << dirtree_dir;
0646 
0647             /*
0648             // debug code
0649 
0650             const QStringList blah = m_sidebarModule->getInterfaces->componentData()->dirs()->dirs()->findDirs( "data", "konqueror/dirtree" );
0651             QStringList::ConstIterator eIt = blah.constBegin();
0652             QStringList::ConstIterator eEnd = blah.constEnd();
0653             for (; eIt != eEnd; ++eIt )
0654             qCDebug(SIDEBAR_LOG) << "findDirs got me " << *eIt;
0655             // end debug code
0656             */
0657 
0658             for (QStringList::const_iterator ddit = dirtree_dirs.constBegin(); ddit != dirtree_dirs.constEnd(); ++ddit) {
0659                 QString dirtree_dir = *ddit;
0660                 if (dirtree_dir == path) {
0661                     continue;
0662                 }
0663                 //    if ( !dirtree_dir.isEmpty() && dirtree_dir != path )
0664                 {
0665                     QDir globalDir(dirtree_dir);
0666                     Q_ASSERT(globalDir.isReadable());
0667                     // Only copy the entries that don't exist yet in the local dir
0668                     const QStringList globalDirEntries = globalDir.entryList();
0669                     QStringList::ConstIterator eIt = globalDirEntries.constBegin();
0670                     QStringList::ConstIterator eEnd = globalDirEntries.constEnd();
0671                     for (; eIt != eEnd; ++eIt) {
0672                         //qCDebug(SIDEBAR_LOG) << "dirtree_dir contains " << *eIt;
0673                         if (*eIt != "." && *eIt != ".."
0674                                 && !entries.contains(*eIt) && !dirEntries.contains(*eIt)) {
0675                             // we don't have that one yet -> copy it.
0676                             QString cp("cp -R -- ");
0677                             cp += KShell::quoteArg(dirtree_dir + *eIt);
0678                             cp += ' ';
0679                             cp += KShell::quoteArg(path);
0680                             qCDebug(SIDEBAR_LOG) << "executing " << cp;
0681                             ::system(QFile::encodeName(cp));
0682                         }
0683                     }
0684                 }
0685             }
0686             // hack to make QDir refresh the lists
0687             dir.setPath(path);
0688             entries = dir.entryList(QDir::Files);
0689             dirEntries = dir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot);
0690         }
0691     }
0692 
0693     // TODO: currently the filename order is used. Implement SortOrder? #69667
0694 
0695     QStringList::ConstIterator eIt = entries.constBegin();
0696     QStringList::ConstIterator eEnd = entries.constEnd();
0697     for (; eIt != eEnd; ++eIt) {
0698         const QString filePath = path + *eIt;
0699         if (KDesktopFile::isDesktopFile(filePath)) {
0700             loadTopLevelItem(parent, filePath);
0701         }
0702     }
0703 
0704     eIt = dirEntries.constBegin();
0705     eEnd = dirEntries.constEnd();
0706 
0707     for (; eIt != eEnd; eIt++) {
0708         const QString newPath = QString(path).append(*eIt).append(QLatin1Char('/'));
0709         loadTopLevelGroup(parent, newPath);
0710     }
0711 }
0712 
0713 void KonqSidebarTree::loadTopLevelGroup(KonqSidebarTreeItem *parent, const QString &path)
0714 {
0715     QDir dir(path);
0716     QString name = dir.dirName();
0717     QString icon = "folder";
0718     bool    open = false;
0719 
0720     qCDebug(SIDEBAR_LOG) << "Scanning " << path;
0721 
0722     QString dotDirectoryFile = QString(path).append("/.directory");
0723 
0724     if (QFile::exists(dotDirectoryFile)) {
0725         qCDebug(SIDEBAR_LOG) << "Reading the .directory";
0726         KDesktopFile cfg(dotDirectoryFile);
0727         const KConfigGroup group = cfg.desktopGroup();
0728         name = group.readEntry("Name", name);
0729         icon = group.readEntry("Icon", icon);
0730         //stripIcon( icon );
0731         open = group.readEntry("Open", open);
0732     }
0733 
0734     KonqSidebarTreeTopLevelItem *item;
0735     if (parent) {
0736         qCDebug(SIDEBAR_LOG) << "Inserting new group under parent ";
0737         item = new KonqSidebarTreeTopLevelItem(parent, 0 /* no module */, path);
0738     } else {
0739         item = new KonqSidebarTreeTopLevelItem(this, 0 /* no module */, path);
0740     }
0741     item->setText(0, name);
0742     item->setPixmap(0, SmallIcon(icon));
0743     item->setListable(false);
0744     item->setClickable(false);
0745     item->setTopLevelGroup(true);
0746     item->setOpen(open);
0747 
0748     m_topLevelItems.append(item);
0749 
0750     qCDebug(SIDEBAR_LOG) << "Inserting group " << name << "   " << path;
0751 
0752     scanDir(item, path);
0753 
0754     if (item->childCount() == 0) {
0755         item->setExpandable(false);
0756     }
0757 }
0758 
0759 void KonqSidebarTree::loadTopLevelItem(KonqSidebarTreeItem *parent, const QString &path)
0760 {
0761     KDesktopFile cfg(path);
0762     KConfigGroup desktopGroup = cfg.desktopGroup();
0763     const QString name = cfg.readName();
0764 
0765     // Here's where we need to create the right module...
0766     // ### TODO: make this KTrader/KLibrary based.
0767     const QString moduleName = desktopGroup.readPathEntry("X-KDE-TreeModule", QString("Directory"));
0768     const QString showHidden = desktopGroup.readEntry("X-KDE-TreeModule-ShowHidden");
0769 
0770     qCDebug(SIDEBAR_LOG) << "##### Loading module: " << moduleName << " file: " << path;
0771 
0772     KonqSidebarTreeModule *module = NULL;
0773     getModule func = getPluginFactory(moduleName);
0774     if (func) {
0775         qCDebug(SIDEBAR_LOG) << "showHidden: " << showHidden;
0776         module = func(this, showHidden.toUpper() == "TRUE");
0777     }
0778 
0779     if (!module) {
0780         qCDebug(SIDEBAR_LOG) << "No Module loaded for" << moduleName;
0781         return;
0782     }
0783 
0784     KonqSidebarTreeTopLevelItem *item;
0785     if (parent) {
0786         item = new KonqSidebarTreeTopLevelItem(parent, module, path);
0787     } else {
0788         item = new KonqSidebarTreeTopLevelItem(this, module, path);
0789     }
0790 
0791     item->setText(0, name);
0792     item->setPixmap(0, SmallIcon(cfg.readIcon()));
0793 
0794     module->addTopLevelItem(item);
0795 
0796     m_topLevelItems.append(item);
0797     m_lstModules.append(module);
0798 
0799     bool open = desktopGroup.readEntry("Open", false);
0800     if (open && item->isExpandable()) {
0801         item->setOpen(true);
0802     }
0803 }
0804 
0805 void KonqSidebarTree::slotAnimation()
0806 {
0807     MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.begin();
0808     MapCurrentOpeningFolders::Iterator end = m_mapCurrentOpeningFolders.end();
0809     for (; it != end; ++it) {
0810         uint &iconNumber = it.value().iconNumber;
0811         QString icon = QString::fromLatin1(it.value().iconBaseName).append(QString::number(iconNumber));
0812         it.key()->setPixmap(0, SmallIcon(icon));
0813 
0814         iconNumber++;
0815         if (iconNumber > it.value().iconCount) {
0816             iconNumber = 1;
0817         }
0818     }
0819 }
0820 
0821 void KonqSidebarTree::startAnimation(KonqSidebarTreeItem *item, const char *iconBaseName, uint iconCount, const QPixmap *originalPixmap)
0822 {
0823     const QPixmap *pix = originalPixmap ? originalPixmap : item->pixmap(0);
0824     if (pix) {
0825         m_mapCurrentOpeningFolders.insert(item, AnimationInfo(iconBaseName, iconCount, *pix));
0826         if (!m_animationTimer->isActive()) {
0827             m_animationTimer->start(50);
0828         }
0829     }
0830 }
0831 
0832 void KonqSidebarTree::stopAnimation(KonqSidebarTreeItem *item)
0833 {
0834     MapCurrentOpeningFolders::Iterator it = m_mapCurrentOpeningFolders.find(item);
0835     if (it != m_mapCurrentOpeningFolders.end()) {
0836         item->setPixmap(0, it.value().originalPixmap);
0837         m_mapCurrentOpeningFolders.remove(item);
0838 
0839         if (m_mapCurrentOpeningFolders.isEmpty()) {
0840             m_animationTimer->stop();
0841         }
0842     }
0843 }
0844 
0845 KonqSidebarTreeItem *KonqSidebarTree::currentItem() const
0846 {
0847     return static_cast<KonqSidebarTreeItem *>(selectedItem());
0848 }
0849 
0850 void KonqSidebarTree::setContentsPos(int x, int y)
0851 {
0852     if (!m_scrollingLocked) {
0853         K3ListView::setContentsPos(x, y);
0854     }
0855 }
0856 
0857 void KonqSidebarTree::slotItemRenamed(Q3ListViewItem *item, const QString &name, int col)
0858 {
0859     Q_ASSERT(col == 0);
0860     if (col != 0) {
0861         return;
0862     }
0863     Q_ASSERT(item);
0864     KonqSidebarTreeItem *treeItem = static_cast<KonqSidebarTreeItem *>(item);
0865     treeItem->rename(name);
0866 }
0867 
0868 void KonqSidebarTree::enableActions(bool copy, bool cut, bool paste)
0869 {
0870     qCDebug(SIDEBAR_LOG) << copy << cut << paste;
0871     m_sidebarModule->enableCopy(copy);
0872     m_sidebarModule->enableCut(cut);
0873     m_sidebarModule->enablePaste(paste);
0874 }
0875 
0876 void KonqSidebarTree::showToplevelContextMenu()
0877 {
0878     KonqSidebarTreeTopLevelItem *item = 0;
0879     KonqSidebarTreeItem *treeItem = currentItem();
0880     if (treeItem && treeItem->isTopLevelItem()) {
0881         item = static_cast<KonqSidebarTreeTopLevelItem *>(treeItem);
0882     }
0883 
0884     QMenu *menu = new QMenu;
0885 
0886     if (item) {
0887         if (item->isTopLevelGroup()) {
0888             menu->addAction(m_collection->action("rename"));
0889             menu->addAction(m_collection->action("delete"));
0890             menu->addSeparator();
0891             menu->addAction(m_collection->action("create_folder"));
0892         } else {
0893             menu->addAction(m_collection->action("open_tab"));
0894             menu->addAction(m_collection->action("open_window"));
0895             menu->addAction(m_collection->action("copy_location"));
0896             menu->addSeparator();
0897             menu->addAction(m_collection->action("rename"));
0898             menu->addAction(m_collection->action("delete_link"));
0899         }
0900         menu->addSeparator();
0901         menu->addAction(m_collection->action("item_properties"));
0902     } else {
0903         menu->addAction(m_collection->action("create_folder"));
0904     }
0905 
0906     m_currentTopLevelItem = item;
0907 
0908     menu->exec(QCursor::pos());
0909     delete menu;
0910 
0911     m_currentTopLevelItem = 0;
0912 }
0913 
0914 void KonqSidebarTree::slotCreateFolder()
0915 {
0916     QString path;
0917     QString name = i18n("New Folder");
0918 
0919     while (true) {
0920         name = KInputDialog::getText(i18nc("@title:window", "Create New Folder"),
0921                                      i18n("Enter folder name:"), name);
0922         if (name.isEmpty()) {
0923             return;
0924         }
0925 
0926         if (m_currentTopLevelItem) {
0927             path = m_currentTopLevelItem->path();
0928         } else {
0929             path = m_dirtreeDir.dir.path();
0930         }
0931 
0932         if (!path.endsWith('/')) {
0933             path += '/';
0934         }
0935 
0936         path = path + name;
0937 
0938         if (!QFile::exists(path)) {
0939             break;
0940         }
0941 
0942         name = name + "-2";
0943     }
0944 
0945     KGlobal::dirs()->makeDir(path);
0946 
0947     loadTopLevelGroup(m_currentTopLevelItem, path);
0948 }
0949 
0950 void KonqSidebarTree::slotDelete()
0951 {
0952     if (currentItem()) {
0953         currentItem()->del();
0954     }
0955 }
0956 
0957 void KonqSidebarTree::slotTrash()
0958 {
0959     if (currentItem()) {
0960         currentItem()->trash();
0961     }
0962 }
0963 
0964 void KonqSidebarTree::slotRename()
0965 {
0966     if (currentItem()) {
0967         currentItem()->rename();
0968     }
0969 }
0970 
0971 void KonqSidebarTree::slotProperties()
0972 {
0973     if (!m_currentTopLevelItem) {
0974         return;
0975     }
0976 
0977     QUrl url(m_currentTopLevelItem->path());
0978 
0979     QPointer<KPropertiesDialog> dlg(new KPropertiesDialog(url, this));
0980     dlg->setFileNameReadOnly(true);
0981     dlg->exec();
0982     delete dlg;
0983 }
0984 
0985 void KonqSidebarTree::slotOpenNewWindow()
0986 {
0987     if (!m_currentTopLevelItem) {
0988         return;
0989     }
0990     emit createNewWindow(m_currentTopLevelItem->externalURL());
0991 }
0992 
0993 void KonqSidebarTree::slotOpenTab()
0994 {
0995     if (!m_currentTopLevelItem) {
0996         return;
0997     }
0998     BrowserArguments browserArgs;
0999     browserArgs.setNewTab(true);
1000     emit createNewWindow(m_currentTopLevelItem->externalURL(),
1001                          KParts::OpenUrlArguments(),
1002                          browserArgs);
1003 }
1004 
1005 static QMimeData *mimeDataFor(const QUrl &url)
1006 {
1007     QMimeData *data = new QMimeData();
1008     QList<QUrl> urlList;
1009     urlList.append(url);
1010     data->setUrls(urlList);
1011     return data;
1012 }
1013 
1014 void KonqSidebarTree::slotCopyLocation()
1015 {
1016     if (!m_currentTopLevelItem) {
1017         return;
1018     }
1019     QUrl url = m_currentTopLevelItem->externalURL();
1020     qApp->clipboard()->setMimeData(mimeDataFor(url), QClipboard::Selection);
1021     qApp->clipboard()->setMimeData(mimeDataFor(url), QClipboard::Clipboard);
1022 }
1023 
1024 ///////////////////////////////////////////////////////////////////
1025 ///////////////////////////////////////////////////////////////////
1026 /*
1027 #ifdef __GNUC__
1028 #warning KonqSidebarTreeToolTip removed, must implemented in event() function
1029 #endif
1030 void KonqSidebarTreeToolTip::maybeTip( const QPoint &point )
1031 {
1032     Q3ListViewItem *item = m_view->itemAt( point );
1033     if ( item ) {
1034         QString text = static_cast<KonqSidebarTreeItem*>( item )->toolTipText();
1035         if ( !text.isEmpty() )
1036             tip ( m_view->itemRect( item ), text );
1037     }
1038 }
1039 */
1040 
1041 bool KonqSidebarTree::overrideShortcut(const QKeyEvent *e)
1042 {
1043     const int key = e->key() | e->modifiers();
1044     if (key == Qt::Key_F2) {
1045         slotRename();
1046         return true;
1047     } else if (key == Qt::Key_Delete) {
1048         qCDebug(SIDEBAR_LOG) << "delete key -> trash";
1049         slotTrash();
1050         return true;
1051     } else if (key == (Qt::SHIFT | Qt::Key_Delete)) {
1052         qCDebug(SIDEBAR_LOG) << "shift+delete -> delete";
1053         slotDelete();
1054         return true;
1055     } else if (KStandardShortcut::copy().contains(key)) {
1056         qCDebug(SIDEBAR_LOG) << "copy";
1057         emit copy();
1058         return true;
1059     } else if (KStandardShortcut::cut().contains(key)) {
1060         qCDebug(SIDEBAR_LOG) << "cut";
1061         emit cut();
1062         return true;
1063     } else if (KStandardShortcut::paste().contains(key)) {
1064         qCDebug(SIDEBAR_LOG) << "paste";
1065         emit paste();
1066         return true;
1067     }
1068     return false;
1069 }
1070 
1071 // For F2 and other shortcuts to work we can't use a QAction; it would conflict with the
1072 // QAction from the active dolphinpart. So we have to use ShortcutOverride.
1073 // Many users requested keyboard shortcuts to work in the sidebar, so it's worth the ugliness (#80584)
1074 bool KonqSidebarTree::eventFilter(QObject *obj, QEvent *ev)
1075 {
1076     if (ev->type() == QEvent::ShortcutOverride) {
1077         QKeyEvent *e = static_cast<QKeyEvent *>(ev);
1078         if (overrideShortcut(e)) {
1079             e->accept();
1080             return true;
1081         }
1082     }
1083     return K3ListView::eventFilter(obj, ev);
1084 }
1085