summaryrefslogtreecommitdiffstats
path: root/kftpgrabber/src/widgets/browser/treeview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kftpgrabber/src/widgets/browser/treeview.cpp')
-rw-r--r--kftpgrabber/src/widgets/browser/treeview.cpp520
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"