/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * 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 #include #include #include 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 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(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(firstChild()); if (item) setCurrentItem(item->fileInfo()); int index = 0; const TQValueList 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(item)->fileInfo(); m_view->rename(fileItem->url(), name); } TQDragObject *DetailsView::dragObject() { KURLDrag *object = static_cast(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(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(item->extraData(this)); if (i) { i->setColor(text); i->setBackground(background); i->repaint(); } } void DetailsView::markItem(KFileItem *item) { ListViewItem *i = static_cast(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(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"