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.
597 lines
16 KiB
597 lines
16 KiB
/*
|
|
* This file is part of the KFTPGrabber project
|
|
*
|
|
* Copyright (C) 2003-2006 by the KFTPGrabber developers
|
|
* Copyright (C) 2003-2006 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/detailsview.h"
|
|
#include "browser/treeview.h"
|
|
#include "browser/view.h"
|
|
#include "browser/locationnavigator.h"
|
|
#include "browser/dirlister.h"
|
|
#include "browser/actions.h"
|
|
|
|
#include "misc/kftpconfig.h"
|
|
#include "misc/kftpapi.h"
|
|
#include "misc/filter.h"
|
|
|
|
#include "kftpqueue.h"
|
|
|
|
#include <tqheader.h>
|
|
#include <tqpainter.h>
|
|
|
|
#include <tdepopupmenu.h>
|
|
#include <kurldrag.h>
|
|
|
|
using namespace KFTPCore::Filter;
|
|
|
|
namespace KFTPWidgets {
|
|
|
|
namespace Browser {
|
|
|
|
DetailsView::DetailsView(TQWidget *parent, View *view, KFTPSession::Session *session)
|
|
: KFileDetailView(parent, 0),
|
|
m_view(view),
|
|
m_treeView(0),
|
|
m_refreshing(false),
|
|
m_shouldDisableResize(true),
|
|
m_autoResizeEnabled(true)
|
|
{
|
|
m_resizeTimer = new TQTimer(this);
|
|
connect(m_resizeTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(updateColumnWidths()));
|
|
|
|
m_dirLister = new DirLister(this);
|
|
m_dirLister->setSession(session);
|
|
|
|
connect(m_dirLister, TQ_SIGNAL(clear()), this, TQ_SLOT(slotClear()));
|
|
connect(m_dirLister, TQ_SIGNAL(completed()), this, TQ_SLOT(slotCompleted()));
|
|
connect(m_dirLister, TQ_SIGNAL(deleteItem(KFileItem*)), this, TQ_SLOT(slotDeleteItem(KFileItem*)));
|
|
connect(m_dirLister, TQ_SIGNAL(refreshItems()), this, TQ_SLOT(slotRefreshItems()));
|
|
connect(m_dirLister, TQ_SIGNAL(siteChanged(const KURL&)), this, TQ_SLOT(slotSiteChanged(const KURL&)));
|
|
|
|
m_navigator = new LocationNavigator(this);
|
|
|
|
connect(m_navigator, TQ_SIGNAL(urlChanged(const KURL&)), this, TQ_SLOT(slotUrlChanged(const KURL&)));
|
|
|
|
connect(this, TQ_SIGNAL(executed(TQListViewItem*)), this, TQ_SLOT(slotItemExecuted()));
|
|
connect(this, TQ_SIGNAL(returnPressed(TQListViewItem*)), this, TQ_SLOT(slotItemExecuted()));
|
|
connect(this, TQ_SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)), this, TQ_SLOT(slotContextMenu(TDEListView*, TQListViewItem*, const TQPoint&)));
|
|
connect(this, TQ_SIGNAL(itemRenamed(TQListViewItem*, const TQString&, int)), this, TQ_SLOT(slotItemRenamed(TQListViewItem*, const TQString&)));
|
|
|
|
// Setup the header
|
|
TQHeader *viewHeader = header();
|
|
viewHeader->setResizeEnabled(true);
|
|
viewHeader->setMovingEnabled(false);
|
|
|
|
connect(viewHeader, TQ_SIGNAL(sizeChange(int, int, int)), this, TQ_SLOT(slotHeaderResized(int)));
|
|
|
|
// Set column width
|
|
setColumnWidthMode(NameColumn, TQListView::Manual);
|
|
setColumnWidthMode(SizeColumn, TQListView::Manual);
|
|
setColumnWidthMode(DateColumn, TQListView::Manual);
|
|
setColumnWidthMode(PermissionsColumn, TQListView::Manual);
|
|
|
|
// Set column alignments
|
|
setColumnAlignment(SizeColumn, TQt::AlignRight);
|
|
setColumnAlignment(DateColumn, TQt::AlignHCenter);
|
|
setColumnAlignment(PermissionsColumn, TQt::AlignHCenter);
|
|
|
|
if (KFTPCore::Config::showOwnerGroup()) {
|
|
setColumnAlignment(OwnerColumn, TQt::AlignHCenter);
|
|
setColumnAlignment(GroupColumn, TQt::AlignHCenter);
|
|
} else {
|
|
// Only show owner/group if set in the config
|
|
removeColumn(4);
|
|
removeColumn(4);
|
|
}
|
|
|
|
setColumnWidth(NameColumn, 140);
|
|
setColumnWidth(DateColumn, 100);
|
|
|
|
setAcceptDrops(true);
|
|
setSelectionMode(KFile::Extended);
|
|
setHScrollBarMode(TQScrollView::AlwaysOff);
|
|
|
|
// Set the defaults
|
|
setHomeUrl(KURL(KFTPCore::Config::defLocalDir()));
|
|
setShowHidden(KFTPCore::Config::showHiddenFiles());
|
|
}
|
|
|
|
DetailsView::~DetailsView()
|
|
{
|
|
}
|
|
|
|
const KURL &DetailsView::url() const
|
|
{
|
|
return m_navigator->url();
|
|
}
|
|
|
|
const TQValueList<LocationNavigator::Element> DetailsView::history(int &index) const
|
|
{
|
|
return m_navigator->history(index);
|
|
}
|
|
|
|
bool DetailsView::isSelected(const KFileItem *i) const
|
|
{
|
|
if (!i)
|
|
return false;
|
|
|
|
const KFileListViewItem *item = static_cast<const KFileListViewItem*>(i->extraData(this));
|
|
return (item && item->isSelected() && item->isVisible());
|
|
}
|
|
|
|
void DetailsView::setTreeView(TreeView *tree)
|
|
{
|
|
m_treeView = tree;
|
|
|
|
connect(m_treeView, TQ_SIGNAL(pathChanged(const KURL&)), this, TQ_SLOT(openUrl(const KURL&)));
|
|
}
|
|
|
|
void DetailsView::setHomeUrl(const KURL &url)
|
|
{
|
|
m_navigator->setHomeUrl(url);
|
|
}
|
|
|
|
void DetailsView::goBack()
|
|
{
|
|
m_navigator->goBack();
|
|
}
|
|
|
|
void DetailsView::goForward()
|
|
{
|
|
m_navigator->goForward();
|
|
}
|
|
|
|
void DetailsView::goUp()
|
|
{
|
|
m_navigator->goUp();
|
|
}
|
|
|
|
void DetailsView::goHome()
|
|
{
|
|
m_navigator->goHome();
|
|
}
|
|
|
|
void DetailsView::endItemUpdates()
|
|
{
|
|
const KFileListViewItem *item = static_cast<const KFileListViewItem*>(firstChild());
|
|
if (item)
|
|
setCurrentItem(item->fileInfo());
|
|
|
|
int index = 0;
|
|
const TQValueList<LocationNavigator::Element> history = m_navigator->history(index);
|
|
if (!history.isEmpty()) {
|
|
KFileView::setCurrentItem(history[index].currentFilename());
|
|
KFileDetailView::setSelected(currentFileItem(), true);
|
|
|
|
// Scroll the contents to last known coordinates
|
|
setContentsPos(history[index].contentsX(), history[index].contentsY());
|
|
}
|
|
|
|
m_treeView->openUrl(m_navigator->url());
|
|
m_treeView->endUpdate(m_navigator->url());
|
|
setFocus();
|
|
}
|
|
|
|
void DetailsView::openUrl(const KURL &url)
|
|
{
|
|
m_navigator->setUrl(url);
|
|
}
|
|
|
|
void DetailsView::slotClear()
|
|
{
|
|
clearView();
|
|
}
|
|
|
|
void DetailsView::slotDeleteItem(KFileItem *item)
|
|
{
|
|
removeItem(item);
|
|
|
|
if (item->isDir())
|
|
m_treeView->removeFolder(item->url());
|
|
}
|
|
|
|
void DetailsView::slotCompleted()
|
|
{
|
|
m_refreshing = true;
|
|
|
|
clearView();
|
|
|
|
KFileItemList items(m_dirLister->items());
|
|
KFileItemListIterator i(items);
|
|
|
|
KFileItem *item = 0;
|
|
while ((item = i.current()) != 0) {
|
|
insertItem(item);
|
|
|
|
if (item->isDir())
|
|
m_treeView->createFolder(item->url(), item->pixmap(16));
|
|
|
|
++i;
|
|
}
|
|
|
|
endItemUpdates();
|
|
m_refreshing = false;
|
|
|
|
m_view->updateActions();
|
|
}
|
|
|
|
void DetailsView::slotRefreshItems()
|
|
{
|
|
TQTimer::singleShot(0, this, TQ_SLOT(reload()));
|
|
}
|
|
|
|
void DetailsView::reload()
|
|
{
|
|
fetchLocation(m_navigator->url(), true);
|
|
}
|
|
|
|
void DetailsView::slotUrlChanged(const KURL &url)
|
|
{
|
|
fetchLocation(url);
|
|
}
|
|
|
|
void DetailsView::slotSiteChanged(const KURL &url)
|
|
{
|
|
m_navigator->clear();
|
|
m_treeView->resetView(url);
|
|
}
|
|
|
|
void DetailsView::fetchLocation(const KURL &url, bool reload)
|
|
{
|
|
m_dirLister->setShowingDotFiles(m_showHidden);
|
|
m_dirLister->fetchLocation(url, reload);
|
|
}
|
|
|
|
void DetailsView::slotContentsMoving(int x, int y)
|
|
{
|
|
if (!m_refreshing)
|
|
emit contentsMoved(x, y);
|
|
}
|
|
|
|
void DetailsView::slotItemExecuted()
|
|
{
|
|
KFileItem *item = currentFileItem();
|
|
|
|
if (item) {
|
|
if (item->isDir())
|
|
openUrl(item->url());
|
|
}
|
|
}
|
|
|
|
void DetailsView::slotHeaderResized(int section)
|
|
{
|
|
if (m_autoResizeEnabled && m_shouldDisableResize && section == 0) {
|
|
setHScrollBarMode(TQScrollView::Auto);
|
|
m_autoResizeEnabled = false;
|
|
}
|
|
}
|
|
|
|
void DetailsView::resizeContents(int width, int height)
|
|
{
|
|
m_shouldDisableResize = false;
|
|
|
|
KFileDetailView::resizeContents(width, height);
|
|
|
|
// Update the column widths
|
|
if (m_autoResizeEnabled) {
|
|
m_resizeTimer->stop();
|
|
m_resizeTimer->start(50, true);
|
|
}
|
|
}
|
|
|
|
void DetailsView::resizeEvent(TQResizeEvent *event)
|
|
{
|
|
m_shouldDisableResize = false;
|
|
|
|
KFileDetailView::resizeEvent(event);
|
|
|
|
// Update the column widths
|
|
if (m_autoResizeEnabled) {
|
|
m_resizeTimer->stop();
|
|
m_resizeTimer->start(50, true);
|
|
}
|
|
}
|
|
|
|
void DetailsView::updateColumnWidths()
|
|
{
|
|
// The code below is based on Dolphin, Copyright (C) 2006 by Peter Penz
|
|
const int columnCount = columns();
|
|
int requiredWidth = 0;
|
|
|
|
for (int i = 1; i < columnCount; ++i) {
|
|
// When a directory contains no items, a minimum width for
|
|
// the column must be available, so that the header is readable.
|
|
int columnWidth = 64;
|
|
TQFontMetrics fontMetrics(font());
|
|
|
|
for (TQListViewItem* item = firstChild(); item != 0; item = item->nextSibling()) {
|
|
const int width = item->width(fontMetrics, this, i);
|
|
|
|
if (width > columnWidth) {
|
|
columnWidth = width;
|
|
}
|
|
}
|
|
|
|
// Add custom margin
|
|
columnWidth += 16;
|
|
setColumnWidth(i, columnWidth);
|
|
requiredWidth += columnWidth;
|
|
}
|
|
|
|
// Resize the first column in a way that the whole available width is used
|
|
int firstColumnWidth = visibleWidth() - requiredWidth;
|
|
if (firstColumnWidth < 128) {
|
|
firstColumnWidth = 128;
|
|
}
|
|
|
|
setColumnWidth(0, firstColumnWidth);
|
|
m_shouldDisableResize = true;
|
|
}
|
|
|
|
void DetailsView::insertItem(KFileItem *fileItem)
|
|
{
|
|
const ActionChain *actionChain = Filters::self()->process(fileItem->url(), fileItem->size(), fileItem->isDir());
|
|
const Action *action;
|
|
|
|
if ((actionChain && actionChain->getAction(Action::Hide)))
|
|
return;
|
|
|
|
KFileView::insertItem(fileItem);
|
|
|
|
ListViewItem *item = new ListViewItem(this, fileItem);
|
|
|
|
if (actionChain && (action = actionChain->getAction(Action::Colorize)))
|
|
item->setColor(action->value().toColor());
|
|
|
|
TQDir::SortSpec spec = KFileView::sorting();
|
|
if (spec & TQDir::Time) {
|
|
item->setKey(sortingKey(fileItem->time(TDEIO::UDS_MODIFICATION_TIME), fileItem->isDir(), spec));
|
|
} else if (spec & TQDir::Size) {
|
|
item->setKey(sortingKey(fileItem->size(), fileItem->isDir(), spec));
|
|
} else {
|
|
item->setKey(sortingKey(fileItem->text(), fileItem->isDir(), spec));
|
|
}
|
|
|
|
fileItem->setExtraData(this, item);
|
|
}
|
|
|
|
void DetailsView::slotContextMenu(TDEListView*, TQListViewItem *i, const TQPoint &p)
|
|
{
|
|
m_view->updateActions();
|
|
|
|
// Create the popup menu
|
|
TDEPopupMenu *menu = new TDEPopupMenu(this);
|
|
|
|
Actions *actions = m_view->m_actions;
|
|
|
|
// Always show create directory
|
|
actions->m_createDirAction->plug(menu);
|
|
menu->insertSeparator();
|
|
|
|
// If nothing is selected, show the navigation menus
|
|
if (!i) {
|
|
actions->m_goUpAction->plug(menu);
|
|
actions->m_goBackAction->plug(menu);
|
|
actions->m_goForwardAction->plug(menu);
|
|
actions->m_reloadAction->plug(menu);
|
|
} else {
|
|
actions->m_transferAction->plug(menu);
|
|
actions->m_queueTransferAction->plug(menu);
|
|
actions->m_renameAction->plug(menu);
|
|
actions->m_deleteAction->plug(menu);
|
|
actions->m_shredAction->plug(menu);
|
|
actions->m_fileEditAction->plug(menu);
|
|
actions->m_verifyAction->plug(menu);
|
|
menu->insertSeparator();
|
|
actions->m_copyAction->plug(menu);
|
|
actions->m_pasteAction->plug(menu);
|
|
menu->insertSeparator();
|
|
actions->m_filterActions->plug(menu);
|
|
}
|
|
|
|
// Always show properties
|
|
menu->insertSeparator();
|
|
actions->m_propsAction->plug(menu);
|
|
|
|
menu->exec(p);
|
|
}
|
|
|
|
void DetailsView::slotItemRenamed(TQListViewItem *item, const TQString &name)
|
|
{
|
|
KFileItem *fileItem = static_cast<KFileListViewItem*>(item)->fileInfo();
|
|
m_view->rename(fileItem->url(), name);
|
|
}
|
|
|
|
TQDragObject *DetailsView::dragObject()
|
|
{
|
|
KURLDrag *object = static_cast<KURLDrag*>(KFileDetailView::dragObject());
|
|
|
|
// Add some metadata
|
|
const KFileItemList *list = KFileView::selectedItems();
|
|
|
|
if (list) {
|
|
KFileItemListIterator i(*list);
|
|
KFileItem *item;
|
|
|
|
while ((item = i.current()) != 0) {
|
|
TQString type = item->isDir() ? "D" : "F";
|
|
object->metaData().insert(item->url().htmlURL().local8Bit(), type + ":" + TDEIO::number(item->size()));
|
|
++i;
|
|
}
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
bool DetailsView::acceptDrag(TQDropEvent *event) const
|
|
{
|
|
return KURLDrag::canDecode(event) &&
|
|
(event->action() == TQDropEvent::Copy ||
|
|
event->action() == TQDropEvent::Move ||
|
|
event->action() == TQDropEvent::Link) &&
|
|
event->source() != this;
|
|
}
|
|
|
|
void DetailsView::contentsDropEvent(TQDropEvent *event)
|
|
{
|
|
if (!acceptDrag(event))
|
|
return;
|
|
|
|
TDEIO::MetaData meta;
|
|
KURL::List urls;
|
|
KURLDrag::decode(event, urls, meta);
|
|
|
|
meta.insert("DestURL", url().url());
|
|
KFTPQueue::Manager::self()->insertTransfer(new KURLDrag(urls, meta, this, name()));
|
|
}
|
|
|
|
KFileItem *DetailsView::fileItem(const TQString &filename)
|
|
{
|
|
if (!filename.isNull()) {
|
|
KFileItem *item;
|
|
|
|
for (item = firstFileItem(); item; item = nextItem(item)) {
|
|
if (item->name() == filename)
|
|
return item;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void DetailsView::setItemVisibility(KFileItem *item, int visibility)
|
|
{
|
|
ListViewItem *i = static_cast<ListViewItem*>(item->extraData(this));
|
|
|
|
if (i) {
|
|
if (visibility != 0 && visibility != 1)
|
|
visibility = !i->isVisible();
|
|
|
|
i->setVisible(visibility);
|
|
}
|
|
}
|
|
|
|
void DetailsView::setItemColor(KFileItem *item, const TQColor &text, const TQColor &background)
|
|
{
|
|
ListViewItem *i = static_cast<ListViewItem*>(item->extraData(this));
|
|
|
|
if (i) {
|
|
i->setColor(text);
|
|
i->setBackground(background);
|
|
i->repaint();
|
|
}
|
|
}
|
|
|
|
void DetailsView::markItem(KFileItem *item)
|
|
{
|
|
ListViewItem *i = static_cast<ListViewItem*>(item->extraData(this));
|
|
|
|
if (i) {
|
|
i->markItem(!i->marked());
|
|
}
|
|
}
|
|
|
|
void DetailsView::markItem(const TQString &filename)
|
|
{
|
|
if (KFileItem *item = fileItem(filename))
|
|
markItem(item);
|
|
}
|
|
|
|
void DetailsView::unmarkItems()
|
|
{
|
|
KFileItem *item;
|
|
|
|
for (item = firstFileItem(); item; item = nextItem(item)) {
|
|
static_cast<ListViewItem*>(item->extraData(this))->markItem(false);
|
|
}
|
|
}
|
|
|
|
DetailsView::ListViewItem::ListViewItem(TQListView *parent, KFileItem *fileItem)
|
|
: KFileListViewItem(parent, fileItem),
|
|
m_marked(false)
|
|
{
|
|
if (fileItem->isDir() && !KFTPCore::Config::showDirectorySize()) {
|
|
setText(SizeColumn, " - ");
|
|
} else {
|
|
TQString sizeText;
|
|
sizeText = KFTPCore::Config::showSizeInBytes() ? TDEIO::number(fileItem->size()) : TDEIO::convertSize(fileItem->size());
|
|
sizeText.append(" ");
|
|
|
|
setText(SizeColumn, sizeText);
|
|
}
|
|
}
|
|
|
|
void DetailsView::ListViewItem::paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment)
|
|
{
|
|
TQColorGroup colorGroup(cg);
|
|
TQColor textColor = colorGroup.text();
|
|
|
|
// Set custom file item color if set
|
|
if (m_textColor.isValid())
|
|
colorGroup.setColor(TQColorGroup::Text, m_textColor);
|
|
|
|
// Set custom file item font
|
|
TQFont font = p->font();
|
|
font.setBold(m_marked);
|
|
p->setFont(font);
|
|
|
|
if (m_backgroundColor.isValid()) {
|
|
colorGroup.setColor(TQColorGroup::Base, m_backgroundColor);
|
|
|
|
// Override the TDEListViewItem since it resets the background color
|
|
TQListViewItem::paintCell(p, colorGroup, column, width, alignment);
|
|
} else {
|
|
KFileListViewItem::paintCell(p, colorGroup, column, width, alignment);
|
|
}
|
|
|
|
if (column < listView()->columns() - 1) {
|
|
// Draw a separator between columns
|
|
p->setPen(TDEGlobalSettings::buttonBackground());
|
|
p->drawLine(width - 1, 0, width - 1, height() - 1);
|
|
}
|
|
}
|
|
|
|
void DetailsView::ListViewItem::markItem(bool marked)
|
|
{
|
|
if (m_marked != marked) {
|
|
m_marked = marked;
|
|
repaint();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#include "detailsview.moc"
|