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/detailsview.cpp

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 <ntqheader.h>
#include <ntqpainter.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, SIGNAL(timeout()), this, SLOT(updateColumnWidths()));
m_dirLister = new DirLister(this);
m_dirLister->setSession(session);
connect(m_dirLister, SIGNAL(clear()), this, SLOT(slotClear()));
connect(m_dirLister, SIGNAL(completed()), this, SLOT(slotCompleted()));
connect(m_dirLister, SIGNAL(deleteItem(KFileItem*)), this, SLOT(slotDeleteItem(KFileItem*)));
connect(m_dirLister, SIGNAL(refreshItems()), this, SLOT(slotRefreshItems()));
connect(m_dirLister, SIGNAL(siteChanged(const KURL&)), this, SLOT(slotSiteChanged(const KURL&)));
m_navigator = new LocationNavigator(this);
connect(m_navigator, SIGNAL(urlChanged(const KURL&)), this, SLOT(slotUrlChanged(const KURL&)));
connect(this, SIGNAL(executed(TQListViewItem*)), this, SLOT(slotItemExecuted()));
connect(this, SIGNAL(returnPressed(TQListViewItem*)), this, SLOT(slotItemExecuted()));
connect(this, SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)), this, SLOT(slotContextMenu(TDEListView*, TQListViewItem*, const TQPoint&)));
connect(this, SIGNAL(itemRenamed(TQListViewItem*, const TQString&, int)), this, SLOT(slotItemRenamed(TQListViewItem*, const TQString&)));
// Setup the header
TQHeader *viewHeader = header();
viewHeader->setResizeEnabled(true);
viewHeader->setMovingEnabled(false);
connect(viewHeader, SIGNAL(sizeChange(int, int, int)), this, 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, SIGNAL(pathChanged(const KURL&)), this, 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, 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"