diff options
Diffstat (limited to 'kftpgrabber/src/widgets/browser/detailsview.cpp')
-rw-r--r-- | kftpgrabber/src/widgets/browser/detailsview.cpp | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/kftpgrabber/src/widgets/browser/detailsview.cpp b/kftpgrabber/src/widgets/browser/detailsview.cpp new file mode 100644 index 0000000..5206d3d --- /dev/null +++ b/kftpgrabber/src/widgets/browser/detailsview.cpp @@ -0,0 +1,596 @@ +/* + * 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/config.h" +#include "misc/kftpapi.h" +#include "misc/filter.h" + +#include "kftpqueue.h" + +#include <qheader.h> +#include <qpainter.h> + +#include <kpopupmenu.h> +#include <kurldrag.h> + +using namespace KFTPCore::Filter; + +namespace KFTPWidgets { + +namespace Browser { + +DetailsView::DetailsView(QWidget *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 QTimer(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(QListViewItem*)), this, SLOT(slotItemExecuted())); + connect(this, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(slotItemExecuted())); + connect(this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&))); + connect(this, SIGNAL(itemRenamed(QListViewItem*, const QString&, int)), this, SLOT(slotItemRenamed(QListViewItem*, const QString&))); + + // Setup the header + QHeader *viewHeader = header(); + viewHeader->setResizeEnabled(true); + viewHeader->setMovingEnabled(false); + + connect(viewHeader, SIGNAL(sizeChange(int, int, int)), this, SLOT(slotHeaderResized(int))); + + // Set column width + setColumnWidthMode(NameColumn, QListView::Manual); + setColumnWidthMode(SizeColumn, QListView::Manual); + setColumnWidthMode(DateColumn, QListView::Manual); + setColumnWidthMode(PermissionsColumn, QListView::Manual); + + // Set column alignments + setColumnAlignment(SizeColumn, Qt::AlignRight); + setColumnAlignment(DateColumn, Qt::AlignHCenter); + setColumnAlignment(PermissionsColumn, Qt::AlignHCenter); + + if (KFTPCore::Config::showOwnerGroup()) { + setColumnAlignment(OwnerColumn, Qt::AlignHCenter); + setColumnAlignment(GroupColumn, Qt::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(QScrollView::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 QValueList<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 QValueList<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() +{ + QTimer::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(QScrollView::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(QResizeEvent *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; + QFontMetrics fontMetrics(font()); + + for (QListViewItem* 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()); + + QDir::SortSpec spec = KFileView::sorting(); + if (spec & QDir::Time) { + item->setKey(sortingKey(fileItem->time(KIO::UDS_MODIFICATION_TIME), fileItem->isDir(), spec)); + } else if (spec & QDir::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(KListView*, QListViewItem *i, const QPoint &p) +{ + m_view->updateActions(); + + // Create the popup menu + KPopupMenu *menu = new KPopupMenu(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(QListViewItem *item, const QString &name) +{ + KFileItem *fileItem = static_cast<KFileListViewItem*>(item)->fileInfo(); + m_view->rename(fileItem->url(), name); +} + +QDragObject *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) { + QString type = item->isDir() ? "D" : "F"; + object->metaData().insert(item->url().htmlURL().local8Bit(), type + ":" + KIO::number(item->size())); + ++i; + } + } + + return object; +} + +bool DetailsView::acceptDrag(QDropEvent *event) const +{ + return KURLDrag::canDecode(event) && + (event->action() == QDropEvent::Copy || + event->action() == QDropEvent::Move || + event->action() == QDropEvent::Link) && + event->source() != this; +} + +void DetailsView::contentsDropEvent(QDropEvent *event) +{ + if (!acceptDrag(event)) + return; + + KIO::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 QString &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 QColor &text, const QColor &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 QString &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(QListView *parent, KFileItem *fileItem) + : KFileListViewItem(parent, fileItem), + m_marked(false) +{ + if (fileItem->isDir() && !KFTPCore::Config::showDirectorySize()) { + setText(SizeColumn, " - "); + } else { + QString sizeText; + sizeText = KFTPCore::Config::showSizeInBytes() ? KIO::number(fileItem->size()) : KIO::convertSize(fileItem->size()); + sizeText.append(" "); + + setText(SizeColumn, sizeText); + } +} + +void DetailsView::ListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) +{ + QColorGroup colorGroup(cg); + QColor textColor = colorGroup.text(); + + // Set custom file item color if set + if (m_textColor.isValid()) + colorGroup.setColor(QColorGroup::Text, m_textColor); + + // Set custom file item font + QFont font = p->font(); + font.setBold(m_marked); + p->setFont(font); + + if (m_backgroundColor.isValid()) { + colorGroup.setColor(QColorGroup::Base, m_backgroundColor); + + // Override the KListViewItem since it resets the background color + QListViewItem::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(KGlobalSettings::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" |