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.
gwenview/src/gvcore/filedetailview.cpp

552 lines
13 KiB

/* This file is based on tdefiledetailview.cpp v1.43 from the KDE libs. Original
copyright follows.
*/
/* This file is part of the KDE libraries
Copyright (C) 1997 Stephan Kulow <coolo@kde.org>
2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
// TQt
#include <tqbitmap.h>
#include <tqevent.h>
#include <tqheader.h>
#include <tqkeycode.h>
#include <tqpainter.h>
#include <tqpixmap.h>
// KDE
#include <tdeapplication.h>
#include <kdebug.h>
#include <tdefileitem.h>
#include <tdeglobalsettings.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <kurldrag.h>
#include <kwordwrap.h>
// Local
#include "archive.h"
#include "dragpixmapgenerator.h"
#include "filedetailviewitem.h"
#include "filedetailview.moc"
#include "timeutils.h"
namespace Gwenview {
static TQPixmap createShownItemPixmap(int size, const TQColor& color) {
TQPixmap pix(size, size);
pix.fill(TQt::red);
TQPainter painter(&pix);
int margin = 2;
TQPointArray pa(3);
int arrowSize = size/2 - margin;
int center = size/2 - 1;
pa[0] = TQPoint((size - arrowSize) / 2, center - arrowSize);
pa[1] = TQPoint((size + arrowSize) / 2, center);
pa[2] = TQPoint(pa[0].x(), center + arrowSize);
painter.setBrush(color);
painter.setPen(color);
painter.drawPolygon(pa);
painter.end();
pix.setMask(pix.createHeuristicMask());
return pix;
}
FileDetailView::FileDetailView(TQWidget *parent, const char *name)
: TDEListView(parent, name), FileViewBase()
{
mSortingCol = COL_NAME;
mBlockSortingSignal = false;
addColumn( i18n( "Name" ) );
addColumn( i18n( "Size" ) );
addColumn( i18n( "Date" ) );
addColumn( i18n( "Permissions" ) );
addColumn( i18n( "Owner" ) );
addColumn( i18n( "Group" ) );
setShowSortIndicator( TRUE );
setAllColumnsShowFocus( TRUE );
connect( header(), TQ_SIGNAL( sectionClicked(int)),
TQ_SLOT(slotSortingChanged(int) ));
connect( this, TQ_SIGNAL( returnPressed(TQListViewItem *) ),
TQ_SLOT( slotActivate( TQListViewItem *) ) );
connect( this, TQ_SIGNAL( clicked(TQListViewItem *, const TQPoint&, int)),
TQ_SLOT( selected( TQListViewItem *) ) );
connect( this, TQ_SIGNAL( doubleClicked(TQListViewItem *, const TQPoint&, int)),
TQ_SLOT( slotActivate( TQListViewItem *) ) );
connect( this, TQ_SIGNAL(contextMenuRequested( TQListViewItem *,
const TQPoint &, int )),
this, TQ_SLOT( slotActivateMenu( TQListViewItem *, const TQPoint& )));
TQListView::setSelectionMode( TQListView::Extended );
connect( this, TQ_SIGNAL( selectionChanged() ),
TQ_SLOT( slotSelectionChanged() ));
// FileViewStack need to be aware of sort changes, to update the sort menu
connect( sig, TQ_SIGNAL(sortingChanged(TQDir::SortSpec)),
this, TQ_SIGNAL(sortingChanged(TQDir::SortSpec)) );
setSorting( sorting() );
mResolver =
new KMimeTypeResolver<FileDetailViewItem,FileDetailView>( this );
setDragEnabled(true);
setAcceptDrops(true);
setDropVisualizer(false);
setDropHighlighter(false);
int size = IconSize(TDEIcon::Small);
mShownItemUnselectedPixmap = createShownItemPixmap(size, colorGroup().highlight());
mShownItemSelectedPixmap = createShownItemPixmap(size, colorGroup().highlightedText());
}
FileDetailView::~FileDetailView()
{
delete mResolver;
}
void FileDetailView::setSelected( const KFileItem *info, bool enable )
{
if (!info) return;
FileDetailViewItem *item = viewItem(info);
if (item) TDEListView::setSelected(item, enable);
}
void FileDetailView::setCurrentItem( const KFileItem *item )
{
if (!item) return;
FileDetailViewItem *listItem = viewItem(item);
if (listItem) TDEListView::setCurrentItem(listItem);
}
KFileItem * FileDetailView::currentFileItem() const
{
FileDetailViewItem *current = static_cast<FileDetailViewItem*>( currentItem() );
if ( current ) return current->fileInfo();
return 0L;
}
void FileDetailView::clearSelection()
{
TDEListView::clearSelection();
}
void FileDetailView::selectAll()
{
TDEListView::selectAll( true );
}
void FileDetailView::invertSelection()
{
TDEListView::invertSelection();
}
void FileDetailView::slotActivateMenu (TQListViewItem *item,const TQPoint& pos )
{
if ( !item ) {
sig->activateMenu( 0, pos );
return;
}
FileDetailViewItem *i = (FileDetailViewItem*) item;
sig->activateMenu( i->fileInfo(), pos );
}
void FileDetailView::clearView()
{
mResolver->m_lstPendingMimeIconItems.clear();
mShownFileItem=0L;
TDEListView::clear();
}
void FileDetailView::insertItem( KFileItem *i )
{
KFileView::insertItem( i );
FileDetailViewItem *item = new FileDetailViewItem( (TQListView*) this, i );
setSortingKey( item, i );
i->setExtraData( this, item );
if ( !i->isMimeTypeKnown() )
mResolver->m_lstPendingMimeIconItems.append( item );
}
void FileDetailView::slotActivate( TQListViewItem *item )
{
if ( !item ) return;
const KFileItem *fi = ( (FileDetailViewItem*)item )->fileInfo();
if ( fi ) sig->activate( fi );
}
void FileDetailView::selected( TQListViewItem *item )
{
if ( !item ) return;
if ( TDEGlobalSettings::singleClick() ) {
const KFileItem *fi = ( (FileDetailViewItem*)item )->fileInfo();
if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) )
sig->activate( fi );
}
}
void FileDetailView::highlighted( TQListViewItem *item )
{
if ( !item ) return;
const KFileItem *fi = ( (FileDetailViewItem*)item )->fileInfo();
if ( fi ) sig->highlightFile( fi );
}
bool FileDetailView::isSelected(const KFileItem* fileItem) const
{
if (!fileItem) return false;
FileDetailViewItem *item = viewItem(fileItem);
return item && item->isSelected();
}
void FileDetailView::updateView( bool b )
{
if ( !b ) return;
TQListViewItemIterator it( (TQListView*)this );
for ( ; it.current(); ++it ) {
FileDetailViewItem *item=static_cast<FileDetailViewItem *>(it.current());
item->setPixmap( 0, item->fileInfo()->pixmap(TDEIcon::SizeSmall) );
}
}
void FileDetailView::updateView( const KFileItem *i, bool /*metaDataOnly*/ )
{
if ( !i ) return;
FileDetailViewItem *item = viewItem(i);
if ( !item ) return;
item->init();
setSortingKey( item, i );
}
void FileDetailView::setSortingKey( FileDetailViewItem *dvItem, const KFileItem *item)
{
TQDir::SortSpec spec = KFileView::sorting();
bool isDirOrArchive=item->isDir() || Archive::fileItemIsArchive(item);
TQString key;
if ( spec & TQDir::Time ) {
time_t time = TimeUtils::getTime(item);
key=sortingKey(time, isDirOrArchive, spec);
} else if ( spec & TQDir::Size ) {
key=sortingKey( item->size(), isDirOrArchive, spec );
} else {
// Name or Unsorted
key=sortingKey( item->text(), isDirOrArchive, spec );
}
dvItem->setKey(key);
}
void FileDetailView::removeItem( const KFileItem *i )
{
if ( !i ) return;
FileDetailViewItem *item = viewItem(i);
mResolver->m_lstPendingMimeIconItems.remove( item );
if(mShownFileItem==i) mShownFileItem=0L;
delete item;
KFileView::removeItem( i );
}
void FileDetailView::slotSortingChanged( int col )
{
TQDir::SortSpec sort = sorting();
int sortSpec = -1;
bool reversed = col == mSortingCol && (sort & TQDir::Reversed) == 0;
mSortingCol = col;
switch( col ) {
case COL_NAME:
sortSpec = ((sort & ~TQDir::SortByMask) | TQDir::Name);
break;
case COL_SIZE:
sortSpec = ((sort & ~TQDir::SortByMask) | TQDir::Size);
break;
case COL_DATE:
sortSpec = ((sort & ~TQDir::SortByMask) | TQDir::Time);
break;
// the following columns have no equivalent in TQDir, so we set it
// to TQDir::Unsorted and remember the column (mSortingCol)
case COL_OWNER:
case COL_GROUP:
case COL_PERM:
// grmbl, TQDir::Unsorted == SortByMask.
sortSpec = (sort & ~TQDir::SortByMask);// | TQDir::Unsorted;
break;
default:
break;
}
if ( reversed )
sortSpec |= TQDir::Reversed;
else
sortSpec &= ~TQDir::Reversed;
if ( sort & TQDir::IgnoreCase )
sortSpec |= TQDir::IgnoreCase;
else
sortSpec &= ~TQDir::IgnoreCase;
KFileView::setSorting( static_cast<TQDir::SortSpec>( sortSpec ) );
KFileItem *item;
KFileItemListIterator it( *items() );
for ( ; (item = it.current() ); ++it ) {
FileDetailViewItem* thumbItem=viewItem( item );
if (thumbItem) setSortingKey(thumbItem,item);
}
TDEListView::setSorting( mSortingCol, !reversed );
TDEListView::sort();
if (!mBlockSortingSignal) sig->changeSorting( static_cast<TQDir::SortSpec>( sortSpec ) );
}
void FileDetailView::setSorting( TQDir::SortSpec spec )
{
int col = 0;
if ( spec & TQDir::Time )
col = COL_DATE;
else if ( spec & TQDir::Size )
col = COL_SIZE;
else if ( spec & TQDir::Unsorted )
col = mSortingCol;
else
col = COL_NAME;
// inversed, because slotSortingChanged will reverse it
if ( spec & TQDir::Reversed )
spec = (TQDir::SortSpec) (spec & ~TQDir::Reversed);
else
spec = (TQDir::SortSpec) (spec | TQDir::Reversed);
mSortingCol = col;
KFileView::setSorting( (TQDir::SortSpec) spec );
// don't emit sortingChanged() when called via setSorting()
mBlockSortingSignal = true; // can't use blockSignals()
slotSortingChanged( col );
mBlockSortingSignal = false;
}
void FileDetailView::ensureItemVisible( const KFileItem *i )
{
if ( !i ) return;
FileDetailViewItem *item = viewItem(i);
if ( item ) TDEListView::ensureItemVisible( item );
}
// we're in multiselection mode
void FileDetailView::slotSelectionChanged()
{
sig->highlightFile( 0L );
}
KFileItem * FileDetailView::firstFileItem() const
{
FileDetailViewItem *item = static_cast<FileDetailViewItem*>( firstChild() );
if ( item ) return item->fileInfo();
return 0L;
}
KFileItem * FileDetailView::nextItem( const KFileItem *fileItem ) const
{
if ( fileItem ) {
FileDetailViewItem *item = viewItem( fileItem );
if ( item && item->itemBelow() )
return ((FileDetailViewItem*) item->itemBelow())->fileInfo();
else
return 0L;
}
else
return firstFileItem();
}
KFileItem * FileDetailView::prevItem( const KFileItem *fileItem ) const
{
if ( fileItem ) {
FileDetailViewItem *item = viewItem( fileItem );
if ( item && item->itemAbove() )
return ((FileDetailViewItem*) item->itemAbove())->fileInfo();
else
return 0L;
}
else
return firstFileItem();
}
void FileDetailView::keyPressEvent( TQKeyEvent *e )
{
TDEListView::keyPressEvent( e );
if ( e->key() == Key_Return || e->key() == Key_Enter ) {
if ( e->state() & ControlButton )
e->ignore();
else
e->accept();
}
}
//
// mimetype determination on demand
//
void FileDetailView::mimeTypeDeterminationFinished()
{
// anything to do?
}
void FileDetailView::determineIcon( FileDetailViewItem *item )
{
(void) item->fileInfo()->determineMimeType();
updateView( item->fileInfo() );
}
void FileDetailView::listingCompleted()
{
mResolver->start();
}
void FileDetailView::startDrag()
{
/**
* The item drawer for DragPixmapGenerator
*/
struct ItemDrawer : public DragPixmapItemDrawer<KFileItem*> {
ItemDrawer(const TQFontMetrics& fontMetrics)
: mFontMetrics(fontMetrics) {}
TQSize itemSize(KFileItem* fileItem) {
if (!fileItem) return TQSize();
TQString name = fileItem->name();
int width = TQMIN(mGenerator->maxWidth(), mFontMetrics.width(name));
int height = mFontMetrics.height();
return TQSize(width, height);
}
void drawItem(TQPainter* painter, int left, int top, KFileItem* fileItem) {
TQString name = fileItem->name();
painter->save();
KWordWrap::drawFadeoutText(painter,
left, top + mFontMetrics.ascent(),
mGenerator->maxWidth(), name);
painter->restore();
}
TQFontMetrics mFontMetrics;
};
ItemDrawer drawer(fontMetrics());
KURL::List urls;
KFileItemListIterator it(*KFileView::selectedItems());
DragPixmapGenerator<KFileItem*> generator;
generator.setItemDrawer(&drawer);
for ( ; it.current(); ++it ) {
urls.append(it.current()->url());
generator.addItem(it.current());
}
if (urls.isEmpty()) {
kdWarning() << "No item to drag\n";
return;
}
TQDragObject* drag=new KURLDrag(urls, this, 0);
TQPixmap dragPixmap = generator.generate();
drag->setPixmap( dragPixmap, TQPoint(-generator.DRAG_OFFSET, -generator.DRAG_OFFSET));
drag->dragCopy();
}
void FileDetailView::setShownFileItem(KFileItem* fileItem)
{
if( fileItem == mShownFileItem ) return;
FileDetailViewItem* oldShownItem=viewItem(mShownFileItem);
FileDetailViewItem* newShownItem=viewItem(fileItem);
FileViewBase::setShownFileItem(fileItem);
if (oldShownItem) oldShownItem->repaint();
if (newShownItem) newShownItem->repaint();
}
//----------------------------------------------------------------------
//
// Drop support
//
//----------------------------------------------------------------------
bool FileDetailView::acceptDrag(TQDropEvent* event) const {
return KURLDrag::canDecode(event);
}
void FileDetailView::contentsDropEvent(TQDropEvent *event) {
KFileItem* fileItem=0L;
TQListViewItem *item=itemAt(contentsToViewport(event->pos() ) );
if (item) {
fileItem=static_cast<FileDetailViewItem*>(item)->fileInfo();
}
emit dropped(event,fileItem);
}
} // namespace