diff options
Diffstat (limited to 'kftpgrabber/src/widgets/browser/treeview.cpp')
-rw-r--r-- | kftpgrabber/src/widgets/browser/treeview.cpp | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/kftpgrabber/src/widgets/browser/treeview.cpp b/kftpgrabber/src/widgets/browser/treeview.cpp new file mode 100644 index 0000000..0f2a824 --- /dev/null +++ b/kftpgrabber/src/widgets/browser/treeview.cpp @@ -0,0 +1,520 @@ +/* + * This file is part of the KFTPGrabber project + * + * Copyright (C) 2003-2004 by the KFTPGrabber developers + * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and + * NON-INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include "browser/treeview.h" +#include "browser/view.h" + +#include "engine/thread.h" + +#include "misc.h" + +#include <qheader.h> +#include <qtimer.h> + +#include <kio/job.h> +#include <kurl.h> +#include <kurldrag.h> + +using namespace KFTPGrabberBase; + +namespace KFTPWidgets { + +namespace Browser { + +/* + * TreeViewItem class + */ + +TreeViewItem::TreeViewItem(TreeView *parent, const KURL &url) + : QListViewItem(parent), + m_tree(parent), + m_url(url), + m_dirty(false) +{ + // Set the name + setText(0, path2Name(url.path(-1))); +} + +TreeViewItem::TreeViewItem(TreeView *tree, QListViewItem *parent, const KURL &url) + : QListViewItem(parent), + m_tree(tree), + m_url(url), + m_dirty(false) +{ + // Set the name + setText(0, path2Name(url.path(-1))); +} + +TreeViewItem::~TreeViewItem() +{ + // The item should be removed from the list as well + m_tree->m_treeItems.remove(m_url.path()); +} + +int TreeViewItem::compare(QListViewItem *i, int col, bool) const +{ + // Hidden files must be on top + if (m_url.fileName().at(0) == '.') + return -1; + + return QListViewItem::compare(i, col, false); +} + +/* + * TreeView class + */ + +TreeView::TreeView(QWidget *parent) + : KListView(parent) +{ + // Create the columns + addColumn(i18n("Directory")); + + // General tree settings + setDragEnabled(true); + setAcceptDrops(true); + setMinimumWidth(150); + setRootIsDecorated(false); + header()->hide(); + + // Reset the view + resetView(KURL("/")); + m_noItemOpen = false; + + // Connect signals + connect(this, SIGNAL(clicked(QListViewItem*)), this, SLOT(slotClicked(QListViewItem*))); + connect(this, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(slotDoubleClicked(QListViewItem*))); + + // Drag and drop + m_dropItem = 0L; +} + + +TreeView::~TreeView() +{ + // Free the item index + m_treeItems.clear(); +} + +void TreeView::resetView(const KURL &url) +{ + // Free the item index + m_treeItems.clear(); + + // Clear the view + clear(); + header()->resizeSection(0, 0); + + // Create the root item + TreeViewItem *rootItem = new TreeViewItem(this, remoteUrl("/", url)); + rootItem->setText(0, url.isLocalFile() ? i18n("Root directory") : url.host()); + rootItem->setPixmap(0, loadSmallPixmap("folder_red")); + setOpen(rootItem, true); +} + +int TreeView::openUrl(const KURL &url, QListViewItem *parent) +{ + // Root item should always be open + setOpen(firstChild(), true); + + // Go trough all items in the list and try to find the url + QListViewItem *item; + if (!parent) + item = firstChild(); + else + item = parent; + + while (item) { + // Check if the item is correct + if (static_cast<TreeViewItem*>(item)->m_url.path(-1) == url.path(-1)) { + // We have found it + ensureItemVisible(item); + setCurrentItem(item); + setSelected(item, true); + + // Change viewport + QRect r = itemRect(item); + if (r.isValid()) { + int x, y; + viewportToContents(contentsX(), r.y(), x, y); + setContentsPos(x, y); + } + + return 1; + } + + if (item->firstChild()) { + // If item has children, go after them + if (openUrl(url, item->firstChild()) == 1) + return 1; + } + + item = item->nextSibling(); + } + + return 0; +} + +QListViewItem *TreeView::findItem(QListViewItem *parent, const QString &name) +{ + QListViewItem *item = parent->firstChild(); + + while (item) { + if (item->text(0) == name) + return item; + + item = item->nextSibling(); + } + + // If nothing is found, parent should be returned + return parent; +} + +void TreeView::createFolder(const KURL &url, QPixmap icon) +{ + int numDirs = url.path(1).contains('/', false); + QListViewItem *item = firstChild(); + + for (int i = 1; i < numDirs; i++) { + QString itemUrl = url.path().section('/', 0, i); + + if (m_treeItems[itemUrl]) { + // Item exists for this URL + item = m_treeItems[itemUrl]; + } else { + // Item not yet created + KURL tmp = url; + tmp.setPath(itemUrl); + + item = new TreeViewItem(this, item, tmp); + if (i == numDirs - 1) + item->setPixmap(0, icon); + else + item->setPixmap(0, loadSmallPixmap("folder")); + + m_treeItems.insert(itemUrl, static_cast<TreeViewItem*>(item)); + } + + // Mark it as dirty + static_cast<TreeViewItem*>(item)->m_dirty = true; + + // Open it + if (!m_noItemOpen) + setOpen(item, true); + } + + // Root item should always be open + setOpen(firstChild(), true); +} + +void TreeView::endUpdate(const KURL &url) +{ + // Remove all items in the selected dir, not marked as dirty + TreeViewItem *top = static_cast<TreeViewItem*>(firstChild()); + TreeViewItem *tmp = 0L; + int numDirs = url.path(1).contains('/', false); + + if (url.path() == "/") { + TreeViewItem *i = static_cast<TreeViewItem*>(top->firstChild()); + + while (i) { + tmp = static_cast<TreeViewItem*>(i->nextSibling()); + + if (!i->m_dirty) { + // Remove item from the index + delete i; + } else { + i->m_dirty = false; + } + + i = tmp; + } + + return; + } + + // URL for items + KURL itemURL = url; + itemURL.setPath("/"); + + for (int i = 1; i < numDirs; i++) { + QString sect = url.path().section('/', i, i); + itemURL.setPath(url.path().section('/', 0, i)); + + if (!m_treeItems[itemURL.path()]) { + // Item not yet created + return; + } else { + // Item is already present + top = m_treeItems[itemURL.path()]; + + // Check for URL match + if (itemURL.path(-1) == url.path(-1)) { + // URL match, delete the item's children + TreeViewItem *i = static_cast<TreeViewItem*>(top->firstChild()); + + while (i) { + tmp = static_cast<TreeViewItem*>(i->nextSibling()); + + if (!i->m_dirty) { + // Remove item from the index + delete i; + } else { + i->m_dirty = false; + } + + i = tmp; + } + return; + } + } + } +} + +void TreeView::clearFolder(const KURL &url) +{ + // Remove url's children + QListViewItem *top = firstChild(); + int numDirs = url.path(1).contains('/', false); + + if (url.path() == "/") { + QListViewItem *i = top->firstChild(); + + while (i) { + // Remove item from the index + delete i; + + i = top->firstChild(); + } + + return; + } + + // URL for items + KURL itemURL = url; + itemURL.setPath("/"); + + for (int i = 1; i < numDirs; i++) { + QString sect = url.path().section('/', i, i); + itemURL.setPath(url.path().section('/', 0, i)); + + if (!m_treeItems[itemURL.path()]) { + // Item not yet created + return; + } else { + // Item is already present + top = m_treeItems[itemURL.path()]; + + // Check for URL match + if (itemURL.path(-1) == url.path(-1)) { + // URL match, delete the item's children + QListViewItem *i = top->firstChild(); + + while (i) { + // Remove item from the index + delete i; + + i = top->firstChild(); + } + return; + } + } + } +} + +void TreeView::removeFolder(const KURL &url) +{ + // Removes a folder at url + QListViewItem *top = firstChild(); + int numDirs = url.path(1).contains('/', false); + + // URL for items + KURL itemURL = url; + itemURL.setPath("/"); + + for (int i = 1; i < numDirs; i++) { + QString sect = url.path().section('/', i, i); + itemURL.setPath(url.path().section('/', 0, i)); + + if (!m_treeItems[itemURL.path()]) { + // Item not yet created + return; + } else { + // Item is already present + top = m_treeItems[itemURL.path()]; + + // Check for URL match + if (itemURL.path(-1) == url.path(-1)) { + // Remove item from the index + delete top; + + return; + } + } + } +} + +void TreeView::slotClicked(QListViewItem *item) +{ + if (!item) + return; + + m_noItemOpen = true; + emit pathChanged(static_cast<TreeViewItem*>(item)->m_url); + m_noItemOpen = false; +} + +void TreeView::slotDoubleClicked(QListViewItem *item) +{ + if (!item) + return; + + setOpen(item, !item->isOpen()); +} + +void TreeView::startDrag() +{ + dragObject()->drag(); +} + +bool TreeView::acceptDrag(QDropEvent *e) +{ + return KURLDrag::canDecode(e) && + ( e->action() == QDropEvent::Copy + || e->action() == QDropEvent::Move + || e->action() == QDropEvent::Link ) + && acceptDrops() + && dragEnabled(); +} + +QDragObject *TreeView::dragObject() +{ + TreeViewItem *item = static_cast<TreeViewItem*>(selectedItem()); + + // Set the correct pixmap + QPixmap pix = *item->pixmap(0); + + KURL::List urls; + urls.append(item->m_url); + + KIO::MetaData meta; + meta.insert(item->m_url.htmlURL().local8Bit(), "D:0"); + + m_dragObject = new KURLDrag(urls, meta, this, name()); + m_dragObject->setPixmap(pix, QPoint(pix.width() / 2, pix.height() / 2)); + + return m_dragObject; +} + +void TreeView::contentsDragEnterEvent(QDragEnterEvent *e) +{ + if (!acceptDrag(e)) { + e->accept(false); + return; + } + + e->acceptAction(); + QListViewItem *i = itemAt(contentsToViewport(e->pos())); + if (i) + m_dropItem = i; +} + +void TreeView::contentsDragMoveEvent(QDragMoveEvent *e) +{ + if (!acceptDrag(e)) { + e->accept(false); + return; + } + + e->acceptAction(); + QListViewItem *i = itemAt(contentsToViewport(e->pos())); + + if (i && i != m_dropItem) + m_dropItem = i; +} + +void TreeView::contentsDragLeaveEvent(QDragLeaveEvent*) +{ + m_dropItem = 0L; +} + +void TreeView::contentsDropEvent(QDropEvent *e) +{ + if (!m_dropItem) + return; + + if (!acceptDrag(e)) { + e->acceptAction(false); + return; + } + e->acceptAction(); + + // Decode the data and try to init transfer + KIO::MetaData meta; + KURL::List urls; + KURLDrag::decode(e, urls, meta); + + // Move the specified file(s) + for (KURL::List::iterator i = urls.begin(); i != urls.end(); ++i) { + KURL destUrl = static_cast<TreeViewItem*>(m_dropItem)->m_url; + + if (destUrl != (*i)) { + if (destUrl.isLocalFile() != (*i).isLocalFile()) { + // TODO Queue up a transfer + } else { + // Rename/move the file + destUrl.addPath((*i).fileName()); + + if ((*i).isLocalFile()) { + KIO::move((*i), destUrl, false); + + // Reload the listing + static_cast<View*>(parent()->parent())->reload(); + } else { + static_cast<View*>(parent()->parent())->m_ftpClient->rename((*i), destUrl); + } + } + } + } + + // Invalidate the drop item + m_dropItem = 0L; +} + +} + +} + +#include "treeview.moc" |