/***************************************************************************
 *   Copyright (C) 2006 by Peter Penz                                      *
 *   peter.penz@gmx.at                                                     *
 *                                                                         *
 *   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 WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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 Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/

#include "dolphindetailsview.h"

#include <kurldrag.h>
#include <tqpainter.h>
#include <tqobjectlist.h>
#include <tqheader.h>
#include <tqclipboard.h>
#include <tqpainter.h>
#include <tdelocale.h>
#include <tdeglobalsettings.h>
#include <tqscrollbar.h>
#include <tqcursor.h>
#include <tqstyle.h>
#include <assert.h>

#include "dolphinview.h"
#include "viewproperties.h"
#include "dolphin.h"
#include "kiconeffect.h"
#include "dolphinsettings.h"
#include "dolphinstatusbar.h"
#include "dolphindetailsviewsettings.h"

DolphinDetailsView::DolphinDetailsView(DolphinView* parent) :
    KFileDetailView(parent, 0),
    m_dolphinView(parent),
    m_resizeTimer(0),
    m_scrollTimer(0),
    m_rubber(0)
{
    m_resizeTimer = new TQTimer(this);
    connect(m_resizeTimer, TQT_SIGNAL(timeout()),
            this, TQT_SLOT(updateColumnsWidth()));

    setAcceptDrops(true);
    setSelectionMode(KFile::Extended);
    setHScrollBarMode(TQScrollView::AlwaysOff);

    setColumnAlignment(SizeColumn, TQt::AlignRight);
    for (int i = DateColumn; i <= GroupColumn; ++i) {
        setColumnAlignment(i, TQt::AlignHCenter);
    }

    Dolphin& dolphin = Dolphin::mainWin();

    connect(this, TQT_SIGNAL(onItem(TQListViewItem*)),
            this, TQT_SLOT(slotOnItem(TQListViewItem*)));
    connect(this, TQT_SIGNAL(onViewport()),
            this, TQT_SLOT(slotOnViewport()));
    connect(this, TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint&, int)),
            this, TQT_SLOT(slotContextMenuRequested(TQListViewItem*, const TQPoint&, int)));
    connect(this, TQT_SIGNAL(selectionChanged()),
            &dolphin, TQT_SLOT(slotSelectionChanged()));
    connect(&dolphin, TQT_SIGNAL(activeViewChanged()),
            this, TQT_SLOT(slotActivationUpdate()));
    connect(this, TQT_SIGNAL(itemRenamed(TQListViewItem*, const TQString&, int)),
            this, TQT_SLOT(slotItemRenamed(TQListViewItem*, const TQString&, int)));
    connect(this, TQT_SIGNAL(dropped(TQDropEvent*, const KURL::List&, const KURL&)),
            parent, TQT_SLOT(slotURLListDropped(TQDropEvent*, const KURL::List&, const KURL&)));

    TQClipboard* clipboard = TQApplication::clipboard();
    connect(clipboard, TQT_SIGNAL(dataChanged()),
            this, TQT_SLOT(slotUpdateDisabledItems()));

    TQHeader* viewHeader = header();
    viewHeader->setResizeEnabled(false);
    viewHeader->setMovingEnabled(false);
    connect(viewHeader, TQT_SIGNAL(clicked(int)),
            this, TQT_SLOT(slotHeaderClicked(int)));

    setMouseTracking(true);
    setDefaultRenameAction(TQListView::Accept);

    refreshSettings();
}

DolphinDetailsView::~DolphinDetailsView()
{
    delete m_rubber;
    m_rubber = 0;
}

void DolphinDetailsView::beginItemUpdates()
{
}

void DolphinDetailsView::endItemUpdates()
{
    updateDisabledItems();

    // Restore the current item. Use the information stored in the history if
    // available. Otherwise use the first item as current item.

    const KFileListViewItem* item = static_cast<const KFileListViewItem*>(firstChild());
    if (item != 0) {
        setCurrentItem(item->fileInfo());
    }

    int index = 0;
    const TQValueList<URLNavigator::HistoryElem> history = m_dolphinView->urlHistory(index);
    if (!history.isEmpty()) {
        KFileView* fileView = static_cast<KFileView*>(this);
        fileView->setCurrentItem(history[index].currentFileName());
        setContentsPos(history[index].contentsX(), history[index].contentsY());
    }

    updateColumnsWidth();
}

void DolphinDetailsView::insertItem(KFileItem* fileItem)
{
    KFileView::insertItem(fileItem);

    DolphinListViewItem* item = new DolphinListViewItem(static_cast<TQListView*>(this), fileItem);

    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);
}

bool DolphinDetailsView::isOnFilename(const TQListViewItem* item, const TQPoint& pos) const
{
    const TQPoint absPos(mapToGlobal(TQPoint(0, 0)));
    return (pos.x() - absPos.x()) <= filenameWidth(item);
}

void DolphinDetailsView::refreshSettings()
{
    const DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
    assert(settings != 0);

    for (int i = DolphinDetailsView::GroupColumn; i >= DolphinDetailsView::NameColumn; --i) {
        if (!settings->isColumnEnabled(i)) {
            removeColumn(i);
        }
    }

    TQFont adjustedFont(font());
    adjustedFont.setFamily(settings->fontFamily());
    adjustedFont.setPointSize(settings->fontSize());
    setFont(adjustedFont);

    updateView(true);
}

void DolphinDetailsView::zoomIn()
{
    if (isZoomInPossible()) {
        DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
        switch (settings->iconSize()) {
            case TDEIcon::SizeSmall:  settings->setIconSize(TDEIcon::SizeMedium); break;
            case TDEIcon::SizeMedium: settings->setIconSize(TDEIcon::SizeLarge); break;
            default: assert(false); break;
        }
        ItemEffectsManager::zoomIn();
    }
}

void DolphinDetailsView::zoomOut()
{
    if (isZoomOutPossible()) {
        DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
        switch (settings->iconSize()) {
            case TDEIcon::SizeLarge:  settings->setIconSize(TDEIcon::SizeMedium); break;
            case TDEIcon::SizeMedium: settings->setIconSize(TDEIcon::SizeSmall); break;
            default: assert(false); break;
        }
        ItemEffectsManager::zoomOut();
    }
}

bool DolphinDetailsView::isZoomInPossible() const
{
    DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
    return settings->iconSize() < TDEIcon::SizeLarge;
}

bool DolphinDetailsView::isZoomOutPossible() const
{
    DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
    return settings->iconSize() > TDEIcon::SizeSmall;
}

void DolphinDetailsView::resizeContents(int width, int height)
{
    KFileDetailView::resizeContents(width, height);

    // When loading several 1000 items a punch of resize events
    // drops in. As updating the column width is a quite expensive
    // operation, this operation will be postponed until there is
    // no resize event for at least 50 milliseconds.
    m_resizeTimer->stop();
    m_resizeTimer->start(50, true);
}

void DolphinDetailsView::slotOnItem(TQListViewItem* item)
{
    if (isOnFilename(item, TQCursor::pos())) {
        activateItem(item);
        KFileItem* fileItem = static_cast<KFileListViewItem*>(item)->fileInfo();
        m_dolphinView->requestItemInfo(fileItem->url());
    }
    else {
        resetActivatedItem();
    }
}

void DolphinDetailsView::slotOnViewport()
{
    resetActivatedItem();
    m_dolphinView->requestItemInfo(KURL());
}

void DolphinDetailsView::setContextPixmap(void* context,
                                        const TQPixmap& pixmap)
{
    reinterpret_cast<KFileListViewItem*>(context)->setPixmap(0, pixmap);
}

const TQPixmap* DolphinDetailsView::contextPixmap(void* context)
{
    return reinterpret_cast<KFileListViewItem*>(context)->pixmap(0);
}

void* DolphinDetailsView::firstContext()
{
    return reinterpret_cast<void*>(firstChild());
}

void* DolphinDetailsView::nextContext(void* context)
{
    KFileListViewItem* listViewItem = reinterpret_cast<KFileListViewItem*>(context);
    return reinterpret_cast<void*>(listViewItem->nextSibling());
}

KFileItem* DolphinDetailsView::contextFileInfo(void* context)
{
    return reinterpret_cast<KFileListViewItem*>(context)->fileInfo();
}


void DolphinDetailsView::contentsDragMoveEvent(TQDragMoveEvent* event)
{
    KFileDetailView::contentsDragMoveEvent(event);

    // If a dragging is done above a directory, show the icon as 'active' for
    // a visual feedback
    KFileListViewItem* item = static_cast<KFileListViewItem*>(itemAt(event->pos()));

    bool showActive = false;
    if (item != 0) {
        const KFileItem* fileInfo = item->fileInfo();
        showActive = (fileInfo != 0) && fileInfo->isDir();
    }

    if (showActive) {
        slotOnItem(item);
    }
    else {
        slotOnViewport();
    }
}

void DolphinDetailsView::resizeEvent(TQResizeEvent* event)
{
    KFileDetailView::resizeEvent(event);

    // When loading several 1000 items a punch of resize events
    // drops in. As updating the column width is a quite expensive
    // operation, this operation will be postponed until there is
    // no resize event for at least 50 milliseconds.
    m_resizeTimer->stop();
    m_resizeTimer->start(50, true);
}

bool DolphinDetailsView::acceptDrag(TQDropEvent* event) const
{
    bool accept = KURLDrag::canDecode(event) &&
                  (event->action() == TQDropEvent::Copy ||
                   event->action() == TQDropEvent::Move ||
                   event->action() == TQDropEvent::Link);
    if (accept) {
        if (static_cast<const TQWidget*>(event->source()) == this) {
            KFileListViewItem* item = static_cast<KFileListViewItem*>(itemAt(event->pos()));
            accept = (item != 0);
            if (accept) {
                KFileItem* fileItem = item->fileInfo();
                accept = fileItem->isDir();
            }
        }
    }

    return accept;
}

void DolphinDetailsView::contentsDropEvent(TQDropEvent* event)
{
    // KFileDetailView::contentsDropEvent does not care whether the mouse
    // cursor is above a filename or not, the destination URL is always
    // the URL of the item. This is fixed here in a way that the destination
    // URL is only the URL of the item if the cursor is above the filename.
    const TQPoint pos(TQCursor::pos());
    const TQPoint viewportPos(viewport()->mapToGlobal(TQPoint(0, 0)));
    TQListViewItem* item = itemAt(TQPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
    if ((item == 0) || ((item != 0) && isOnFilename(item, pos))) {
        // dropping is done on the viewport or directly above a filename
        KFileDetailView::contentsDropEvent(event);
        return;
    }

    // Dropping is done above an item, but the mouse cursor is not above the file name.
    // In this case the signals of the base implementation will be blocked and send
    // in a corrected manner afterwards.
    assert(item != 0);
    const bool block = signalsBlocked();
    blockSignals(true);
    KFileDetailView::contentsDropEvent(event);
    blockSignals(block);

    if (!acceptDrag(event)) {
        return;
    }

    emit dropped(event, 0);
    KURL::List urls;
    if (KURLDrag::decode(event, urls) && !urls.isEmpty()) {
        emit dropped(event, urls, KURL());
        sig->dropURLs(0, event, urls);
    }
}

void DolphinDetailsView::contentsMousePressEvent(TQMouseEvent* event)
{
    if (m_rubber != 0) {
        drawRubber();
        delete m_rubber;
        m_rubber = 0;
    }

    // Swallow the base implementation of the mouse press event
    // if the mouse cursor is not above the filename. This prevents
    // that the item gets selected and simulates an equal usability
    // like in the icon view.
    const TQPoint pos(TQCursor::pos());
    const TQPoint viewportPos(viewport()->mapToGlobal(TQPoint(0, 0)));
    TQListViewItem* item = itemAt(TQPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
    if ((item != 0) && isOnFilename(item, pos)) {
        KFileDetailView::contentsMousePressEvent(event);
    }
    else if (event->button() == Qt::LeftButton) {
        const ButtonState keyboardState = TDEApplication::keyboardMouseState();
        const bool isSelectionActive = (keyboardState & ShiftButton) ||
                                       (keyboardState & ControlButton);
        if (!isSelectionActive) {
            clearSelection();
        }

        assert(m_rubber == 0);
        m_rubber = new TQRect(event->x(), event->y(), 0, 0);
    }

    resetActivatedItem();
    emit signalRequestActivation();

    m_dolphinView->statusBar()->clear();
}

void DolphinDetailsView::contentsMouseMoveEvent(TQMouseEvent* event)
{
    if (m_rubber != 0) {
        slotAutoScroll();
        return;
    }

    KFileDetailView::contentsMouseMoveEvent(event);

    const TQPoint& pos = event->globalPos();
    const TQPoint viewportPos = viewport()->mapToGlobal(TQPoint(0, 0));
    TQListViewItem* item = itemAt(TQPoint(pos.x() - viewportPos.x(), pos.y() - viewportPos.y()));
    if ((item != 0) && isOnFilename(item, pos)) {
        activateItem(item);
    }
    else {
        resetActivatedItem();
    }
}

void DolphinDetailsView::contentsMouseReleaseEvent(TQMouseEvent* event)
{
    if (m_rubber != 0) {
        drawRubber();
        delete m_rubber;
        m_rubber = 0;
    }

    if (m_scrollTimer != 0) {
        disconnect(m_scrollTimer, TQT_SIGNAL(timeout()),
                    this, TQT_SLOT(slotAutoScroll()));
        m_scrollTimer->stop();
        delete m_scrollTimer;
        m_scrollTimer = 0;
    }

    KFileDetailView::contentsMouseReleaseEvent(event);
}

void DolphinDetailsView::paintEmptyArea(TQPainter* painter, const TQRect& rect)
{
    if (m_dolphinView->isActive()) {
        KFileDetailView::paintEmptyArea(painter, rect);
    }
    else {
        const TQBrush brush(colorGroup().background());
        painter->fillRect(rect, brush);
    }
}

void DolphinDetailsView::drawRubber()
{
    // Parts of the following code have been taken
    // from the class KonqBaseListViewWidget located in
    // konqueror/listview/konq_listviewwidget.h of Konqueror.
    // (Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
    //  2001, 2002, 2004 Michael Brade <brade@kde.org>)
    if (m_rubber == 0) {
        return;
    }

    TQPainter p;
    p.begin(viewport());
    p.setRasterOp(NotROP);
    p.setPen(TQPen(color0, 1));
    p.setBrush(NoBrush);

    TQPoint point(m_rubber->x(), m_rubber->y());
    point = contentsToViewport(point);
    style().tqdrawPrimitive(TQStyle::PE_FocusRect, &p,
                          TQRect(point.x(), point.y(), m_rubber->width(), m_rubber->height()),
                          colorGroup(), TQStyle::Style_Default, colorGroup().base());
    p.end();
}

void DolphinDetailsView::viewportPaintEvent(TQPaintEvent* paintEvent)
{
    drawRubber();
    KFileDetailView::viewportPaintEvent(paintEvent);
    drawRubber();
}

void DolphinDetailsView::leaveEvent(TQEvent* event)
{
    KFileDetailView::leaveEvent(event);
    slotOnViewport();
}

void DolphinDetailsView::slotActivationUpdate()
{
    update();

    // TODO: there must be a simpler way to say
    // "update all children"
    const TQObjectList list = childrenListObject();
    if (list.isEmpty()) {
        return;
    }

    TQObjectListIterator it(list);
    TQObject* object = 0;
    while ((object = it.current()) != 0) {
        if (object->inherits(TQWIDGET_OBJECT_NAME_STRING)) {
            TQWidget* widget = TQT_TQWIDGET(object);
            widget->update();
        }
        ++it;
    }
}

void DolphinDetailsView::slotContextMenuRequested(TQListViewItem* item,
                                                  const TQPoint& pos,
                                                  int /* col */)
{
    KFileItem* fileInfo = 0;
    if ((item != 0) && isOnFilename(item, pos)) {
        fileInfo = static_cast<KFileListViewItem*>(item)->fileInfo();
    }
    m_dolphinView->openContextMenu(fileInfo, pos);

}

void DolphinDetailsView::slotUpdateDisabledItems()
{
    updateDisabledItems();
}

void DolphinDetailsView::slotAutoScroll()
{
    // Parts of the following code have been taken
    // from the class KonqBaseListViewWidget located in
    // konqueror/listview/konq_listviewwidget.h of Konqueror.
    // (Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
    //  2001, 2002, 2004 Michael Brade <brade@kde.org>)

    const TQPoint pos(viewport()->mapFromGlobal(TQCursor::pos()));
    const TQPoint vc(viewportToContents(pos));

    if (vc == m_rubber->bottomRight()) {
        return;
    }

    drawRubber();

    m_rubber->setBottomRight(vc);

    TQListViewItem* item = itemAt(TQPoint(0,0));

    const bool block = signalsBlocked();
    blockSignals(true);

    const TQRect rubber(m_rubber->normalize());
    const int bottom = contentsY() + visibleHeight() - 1;

    // select all items which intersect with the rubber, deselect all others
    bool bottomReached = false;
    while ((item != 0) && !bottomReached) {
        TQRect rect(itemRect(item));
        rect.setWidth(filenameWidth(item));
        rect = TQRect(viewportToContents(rect.topLeft()),
                     viewportToContents(rect.bottomRight()));
        if (rect.isValid() && (rect.top() <= bottom)) {
            const KFileItem* fileItem = static_cast<KFileListViewItem*>(item)->fileInfo();
            setSelected(fileItem, rect.intersects(rubber));
            item = item->itemBelow();
        }
        else {
            bottomReached = true;
        }
    }

    blockSignals(block);
    emit selectionChanged();

    drawRubber();

    // scroll the viewport if the top or bottom margin is reached
    const int scrollMargin = 40;
    ensureVisible(vc.x(), vc.y(), scrollMargin, scrollMargin);
    const bool scroll = !TQRect(scrollMargin,
                               scrollMargin,
                               viewport()->width()  - 2 * scrollMargin,
                               viewport()->height() - 2 * scrollMargin).contains(pos);
    if (scroll) {
        if (m_scrollTimer == 0) {
            m_scrollTimer = new TQTimer( this );
            connect(m_scrollTimer, TQT_SIGNAL(timeout()),
                    this, TQT_SLOT(slotAutoScroll()));
            m_scrollTimer->start(100, false);
        }
    }
    else if (m_scrollTimer != 0) {
        disconnect(m_scrollTimer, TQT_SIGNAL(timeout()),
                   this, TQT_SLOT(slotAutoScroll()));
        m_scrollTimer->stop();
        delete m_scrollTimer;
        m_scrollTimer = 0;
    }
}

void DolphinDetailsView::updateColumnsWidth()
{
    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.
        // TODO: use header data instead of the hardcoded 64 value...
        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;
            }
        }
        columnWidth += 16;    // add custom margin
        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);
}

void DolphinDetailsView::slotItemRenamed(TQListViewItem* item,
                                         const TQString& name,
                                         int /* column */)
{
    KFileItem* fileInfo = static_cast<KFileListViewItem*>(item)->fileInfo();
    m_dolphinView->rename(KURL(fileInfo->url()), name);
}

void DolphinDetailsView::slotHeaderClicked(int /* section */)
{
    // The sorting has already been changed in TQListView if this slot is
    // invoked, but Dolphin was not informed about this (no signal is available
    // which indicates a change of the sorting). This is bypassed by changing
    // the sorting and sort order to a temporary other value and readjust it again.
    const int column = sortColumn();
    if (column <= DateColumn) {
        DolphinView::Sorting sorting = DolphinView::SortByName;
        switch (column) {
            case SizeColumn: sorting = DolphinView::SortBySize; break;
            case DateColumn: sorting = DolphinView::SortByDate; break;
            case NameColumn:
            default: break;
        }

        const TQt::SortOrder currSortOrder = sortOrder();

        // temporary adjust the sorting and sort order to different values...
        const DolphinView::Sorting tempSorting = (sorting == DolphinView::SortByName) ?
                                                 DolphinView::SortBySize :
                                                 DolphinView::SortByName;
        m_dolphinView->setSorting(tempSorting);
        const TQt::SortOrder tempSortOrder = (currSortOrder == TQt::Ascending) ?
                                            TQt::Descending : TQt::Ascending;
        m_dolphinView->setSortOrder(tempSortOrder);

        // ... so that setting them again results in storing the new setting.
        m_dolphinView->setSorting(sorting);
        m_dolphinView->setSortOrder(currSortOrder);
    }
}

DolphinDetailsView::DolphinListViewItem::DolphinListViewItem(TQListView* parent,
                                                             KFileItem* fileItem) :
    KFileListViewItem(parent, fileItem)
{
    const int iconSize = DolphinSettings::instance().detailsView()->iconSize();
    KFileItem* info = fileInfo();
    setPixmap(DolphinDetailsView::NameColumn, info->pixmap(iconSize));

    // The base class KFileListViewItem represents the column 'Size' only as byte values.
    // Adjust those values in a way that a mapping to GBytes, MBytes, KBytes and Bytes
    // is done. As the file size for directories is useless (only the size of the directory i-node
    // is given), it is removed completely.
    if (fileItem->isDir()) {
        setText(SizeColumn, " - ");
    }
    else {
        TQString sizeText(TDEIO::convertSize(fileItem->size()));
        sizeText.append(" ");
        setText(SizeColumn, sizeText);
    }

    // Dolphin allows to remove specific columns, but the base class KFileListViewItem
    // is not aware about this (or at least the class KFileDetailView does not react on
    // TQListView::remove()). Therefore the columns are rearranged here.
    const DolphinDetailsViewSettings* settings = DolphinSettings::instance().detailsView();
    assert(settings != 0);

    int column_idx = DateColumn;    // the columns for 'name' and 'size' cannot get removed
    for (int i = DolphinDetailsView::DateColumn; i <= DolphinDetailsView::GroupColumn; ++i) {
        if (column_idx < i) {
            setText(column_idx, text(i));
        }
        if (settings->isColumnEnabled(i)) {
            ++column_idx;
        }
    }
}

DolphinDetailsView::DolphinListViewItem::~DolphinListViewItem()
{
}

void DolphinDetailsView::DolphinListViewItem::paintCell(TQPainter* painter,
                                                        const TQColorGroup& colorGroup,
                                                        int column,
                                                        int cellWidth,
                                                        int alignment)
{
    const TQListView* view = listView();
    const bool isActive = TQT_BASE_OBJECT(view->parent()) == TQT_BASE_OBJECT(Dolphin::mainWin().activeView());
    if (isSelected()) {
        // Per default the selection is drawn above the whole width of the item. As a consistent
        // behavior with the icon view is wanted, only the the column containing the file name
        // should be shown as selected.
        TQColorGroup defaultColorGroup(colorGroup);
        const TQColor highlightColor(isActive ? backgroundColor(column) : view->colorGroup().background());
        defaultColorGroup.setColor(TQColorGroup::Highlight , highlightColor);
        defaultColorGroup.setColor(TQColorGroup::HighlightedText, colorGroup.color(TQColorGroup::Text));
        KFileListViewItem::paintCell(painter, defaultColorGroup, column, cellWidth, alignment);

        if (column == 0) {
            // draw the selection only on the first column
            TQListView* parent = listView();
            const int itemWidth = width(parent->fontMetrics(), parent, 0);
            if (isActive) {
                KFileListViewItem::paintCell(painter, colorGroup, column, itemWidth, alignment);
            }
            else {
                TQListViewItem::paintCell(painter, colorGroup, column, itemWidth, alignment);
            }
        }
    }
    else {
        if (isActive) {
            KFileListViewItem::paintCell(painter, colorGroup, column, cellWidth, alignment);
        }
        else {
            TQListViewItem::paintCell(painter, colorGroup, column, cellWidth, alignment);
        }
    }

    if (column < listView()->columns() - 1) {
        // draw a separator between columns
        painter->setPen(TDEGlobalSettings::buttonBackground());
        painter->drawLine(cellWidth - 1, 0, cellWidth - 1, height() - 1);
    }
}

void DolphinDetailsView::DolphinListViewItem::paintFocus(TQPainter* painter,
                                                         const TQColorGroup& colorGroup,
                                                         const TQRect& rect)
{
    // draw the focus consistently with the selection (see implementation notes
    // in DolphinListViewItem::paintCell)
    TQListView* parent = listView();
    int visibleWidth = width(parent->fontMetrics(), parent, 0);
    const int colWidth = parent->columnWidth(0);
    if (visibleWidth > colWidth) {
        visibleWidth = colWidth;
    }

    TQRect focusRect(rect);
    focusRect.setWidth(visibleWidth);

    KFileListViewItem::paintFocus(painter, colorGroup, focusRect);
}

int DolphinDetailsView::filenameWidth(const TQListViewItem* item) const
{
    assert(item != 0);

    int visibleWidth = item->width(fontMetrics(), this, 0);
    const int colWidth = columnWidth(0);
    if (visibleWidth > colWidth) {
        visibleWidth = colWidth;
    }

    return visibleWidth;
}
#include "dolphindetailsview.moc"