You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kftpgrabber/kftpgrabber/src/widgets/browser/treeview.cpp

521 lines
12 KiB

/*
* 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 <tqheader.h>
#include <tqtimer.h>
#include <tdeio/job.h>
#include <kurl.h>
#include <kurldrag.h>
using namespace KFTPGrabberBase;
namespace KFTPWidgets {
namespace Browser {
/*
* TreeViewItem class
*/
TreeViewItem::TreeViewItem(TreeView *parent, const KURL &url)
: TQListViewItem(parent),
m_tree(parent),
m_url(url),
m_dirty(false)
{
// Set the name
setText(0, path2Name(url.path(-1)));
}
TreeViewItem::TreeViewItem(TreeView *tree, TQListViewItem *parent, const KURL &url)
: TQListViewItem(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(TQListViewItem *i, int col, bool) const
{
// Hidden files must be on top
if (m_url.fileName().at(0) == '.')
return -1;
return TQListViewItem::compare(i, col, false);
}
/*
* TreeView class
*/
TreeView::TreeView(TQWidget *parent)
: TDEListView(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, TQ_SIGNAL(clicked(TQListViewItem*)), this, TQ_SLOT(slotClicked(TQListViewItem*)));
connect(this, TQ_SIGNAL(doubleClicked(TQListViewItem*)), this, TQ_SLOT(slotDoubleClicked(TQListViewItem*)));
// 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, TQListViewItem *parent)
{
// Root item should always be open
setOpen(firstChild(), true);
// Go trough all items in the list and try to find the url
TQListViewItem *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
TQRect 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;
}
TQListViewItem *TreeView::findItem(TQListViewItem *parent, const TQString &name)
{
TQListViewItem *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, TQPixmap icon)
{
int numDirs = url.path(1).contains('/', false);
TQListViewItem *item = firstChild();
for (int i = 1; i < numDirs; i++) {
TQString 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++) {
TQString 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
TQListViewItem *top = firstChild();
int numDirs = url.path(1).contains('/', false);
if (url.path() == "/") {
TQListViewItem *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++) {
TQString 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
TQListViewItem *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
TQListViewItem *top = firstChild();
int numDirs = url.path(1).contains('/', false);
// URL for items
KURL itemURL = url;
itemURL.setPath("/");
for (int i = 1; i < numDirs; i++) {
TQString 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(TQListViewItem *item)
{
if (!item)
return;
m_noItemOpen = true;
emit pathChanged(static_cast<TreeViewItem*>(item)->m_url);
m_noItemOpen = false;
}
void TreeView::slotDoubleClicked(TQListViewItem *item)
{
if (!item)
return;
setOpen(item, !item->isOpen());
}
void TreeView::startDrag()
{
dragObject()->drag();
}
bool TreeView::acceptDrag(TQDropEvent *e)
{
return KURLDrag::canDecode(e) &&
( e->action() == TQDropEvent::Copy
|| e->action() == TQDropEvent::Move
|| e->action() == TQDropEvent::Link )
&& acceptDrops()
&& dragEnabled();
}
TQDragObject *TreeView::dragObject()
{
TreeViewItem *item = static_cast<TreeViewItem*>(selectedItem());
// Set the correct pixmap
TQPixmap pix = *item->pixmap(0);
KURL::List urls;
urls.append(item->m_url);
TDEIO::MetaData meta;
meta.insert(item->m_url.htmlURL().local8Bit(), "D:0");
m_dragObject = new KURLDrag(urls, meta, this, name());
m_dragObject->setPixmap(pix, TQPoint(pix.width() / 2, pix.height() / 2));
return m_dragObject;
}
void TreeView::contentsDragEnterEvent(TQDragEnterEvent *e)
{
if (!acceptDrag(e)) {
e->accept(false);
return;
}
e->acceptAction();
TQListViewItem *i = itemAt(contentsToViewport(e->pos()));
if (i)
m_dropItem = i;
}
void TreeView::contentsDragMoveEvent(TQDragMoveEvent *e)
{
if (!acceptDrag(e)) {
e->accept(false);
return;
}
e->acceptAction();
TQListViewItem *i = itemAt(contentsToViewport(e->pos()));
if (i && i != m_dropItem)
m_dropItem = i;
}
void TreeView::contentsDragLeaveEvent(TQDragLeaveEvent*)
{
m_dropItem = 0L;
}
void TreeView::contentsDropEvent(TQDropEvent *e)
{
if (!m_dropItem)
return;
if (!acceptDrag(e)) {
e->acceptAction(false);
return;
}
e->acceptAction();
// Decode the data and try to init transfer
TDEIO::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()) {
TDEIO::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"