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.
521 lines
12 KiB
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"
|