kfiledetailview.cpp
// -*- c++ -*-
/* 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.
*/
#include <qevent.h>
#include <qkeycode.h>
#include <qheader.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <kapplication.h>
#include <kfileitem.h>
#include <kglobal.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <kicontheme.h>
#include <klocale.h>
#include <kdebug.h>
#include <kurldrag.h>
#include "kfiledetailview.h"
#include "config-kfile.h"
#define COL_NAME 0
#define COL_SIZE 1
#define COL_DATE 2
#define COL_PERM 3
#define COL_OWNER 4
#define COL_GROUP 5
class KFileDetailView::KFileDetailViewPrivate
{
public:
KFileDetailViewPrivate() : dropItem(0)
{ }
KFileListViewItem *dropItem;
QTimer autoOpenTimer;
};
KFileDetailView::KFileDetailView(QWidget *parent, const char *name)
: KListView(parent, name), KFileView(), d(new KFileDetailViewPrivate())
{
// this is always the static section, not the index depending on column order
m_sortingCol = COL_NAME;
m_blockSortingSignal = false;
setViewName( i18n("Detailed View") );
addColumn( i18n( "Name" ) );
addColumn( i18n( "Size" ) );
addColumn( i18n( "Date" ) );
addColumn( i18n( "Permissions" ) );
addColumn( i18n( "Owner" ) );
addColumn( i18n( "Group" ) );
setShowSortIndicator( true );
setAllColumnsShowFocus( true );
setDragEnabled(true);
connect( header(), SIGNAL( clicked(int)),
SLOT(slotSortingChanged(int) ));
connect( this, SIGNAL( returnPressed(QListViewItem *) ),
SLOT( slotActivate( QListViewItem *) ) );
connect( this, SIGNAL( clicked(QListViewItem *, const QPoint&, int)),
SLOT( selected( QListViewItem *) ) );
connect( this, SIGNAL( doubleClicked(QListViewItem *, const QPoint&, int)),
SLOT( slotActivate( QListViewItem *) ) );
connect( this, SIGNAL(contextMenuRequested( QListViewItem *,
const QPoint &, int )),
this, SLOT( slotActivateMenu( QListViewItem *, const QPoint& )));
KFile::SelectionMode sm = KFileView::selectionMode();
switch ( sm ) {
case KFile::Multi:
QListView::setSelectionMode( QListView::Multi );
break;
case KFile::Extended:
QListView::setSelectionMode( QListView::Extended );
break;
case KFile::NoSelection:
QListView::setSelectionMode( QListView::NoSelection );
break;
default: // fall through
case KFile::Single:
QListView::setSelectionMode( QListView::Single );
break;
}
// for highlighting
if ( sm == KFile::Multi || sm == KFile::Extended )
connect( this, SIGNAL( selectionChanged() ),
SLOT( slotSelectionChanged() ));
else
connect( this, SIGNAL( selectionChanged( QListViewItem * ) ),
SLOT( highlighted( QListViewItem * ) ));
// DND
connect( &(d->autoOpenTimer), SIGNAL( timeout() ),
this, SLOT( slotAutoOpen() ));
setSorting( sorting() );
m_resolver =
new KMimeTypeResolver<KFileListViewItem,KFileDetailView>( this );
}
KFileDetailView::~KFileDetailView()
{
delete m_resolver;
delete d;
}
void KFileDetailView::readConfig( KConfig *config, const QString& group )
{
restoreLayout( config, group );
}
void KFileDetailView::writeConfig( KConfig *config, const QString& group )
{
saveLayout( config, group );
}
void KFileDetailView::setSelected( const KFileItem *info, bool enable )
{
if ( !info )
return;
// we can only hope that this casts works
KFileListViewItem *item = (KFileListViewItem*)info->extraData( this );
if ( item )
KListView::setSelected( item, enable );
}
void KFileDetailView::setCurrentItem( const KFileItem *item )
{
if ( !item )
return;
KFileListViewItem *it = (KFileListViewItem*) item->extraData( this );
if ( it )
KListView::setCurrentItem( it );
}
KFileItem * KFileDetailView::currentFileItem() const
{
KFileListViewItem *current = static_cast<KFileListViewItem*>( currentItem() );
if ( current )
return current->fileInfo();
return 0L;
}
void KFileDetailView::clearSelection()
{
KListView::clearSelection();
}
void KFileDetailView::selectAll()
{
if (KFileView::selectionMode() == KFile::NoSelection ||
KFileView::selectionMode() == KFile::Single)
return;
KListView::selectAll( true );
}
void KFileDetailView::invertSelection()
{
KListView::invertSelection();
}
void KFileDetailView::slotActivateMenu (QListViewItem *item,const QPoint& pos )
{
if ( !item ) {
sig->activateMenu( 0, pos );
return;
}
KFileListViewItem *i = (KFileListViewItem*) item;
sig->activateMenu( i->fileInfo(), pos );
}
void KFileDetailView::clearView()
{
m_resolver->m_lstPendingMimeIconItems.clear();
KListView::clear();
}
void KFileDetailView::insertItem( KFileItem *i )
{
KFileView::insertItem( i );
KFileListViewItem *item = new KFileListViewItem( (QListView*) this, i );
setSortingKey( item, i );
i->setExtraData( this, item );
if ( !i->isMimeTypeKnown() )
m_resolver->m_lstPendingMimeIconItems.append( item );
}
void KFileDetailView::slotActivate( QListViewItem *item )
{
if ( !item )
return;
const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
if ( fi )
sig->activate( fi );
}
void KFileDetailView::selected( QListViewItem *item )
{
if ( !item )
return;
if ( KGlobalSettings::singleClick() ) {
const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
if ( fi && (fi->isDir() || !onlyDoubleClickSelectsFiles()) )
sig->activate( fi );
}
}
void KFileDetailView::highlighted( QListViewItem *item )
{
if ( !item )
return;
const KFileItem *fi = ( (KFileListViewItem*)item )->fileInfo();
if ( fi )
sig->highlightFile( fi );
}
void KFileDetailView::setSelectionMode( KFile::SelectionMode sm )
{
disconnect( this, SIGNAL( selectionChanged() ));
disconnect( this, SIGNAL( selectionChanged( QListViewItem * ) ));
KFileView::setSelectionMode( sm );
switch ( KFileView::selectionMode() ) {
case KFile::Multi:
QListView::setSelectionMode( QListView::Multi );
break;
case KFile::Extended:
QListView::setSelectionMode( QListView::Extended );
break;
case KFile::NoSelection:
QListView::setSelectionMode( QListView::NoSelection );
break;
default: // fall through
case KFile::Single:
QListView::setSelectionMode( QListView::Single );
break;
}
if ( sm == KFile::Multi || sm == KFile::Extended )
connect( this, SIGNAL( selectionChanged() ),
SLOT( slotSelectionChanged() ));
else
connect( this, SIGNAL( selectionChanged( QListViewItem * )),
SLOT( highlighted( QListViewItem * )));
}
bool KFileDetailView::isSelected( const KFileItem *i ) const
{
if ( !i )
return false;
KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
return (item && item->isSelected());
}
void KFileDetailView::updateView( bool b )
{
if ( !b )
return;
QListViewItemIterator it( (QListView*)this );
for ( ; it.current(); ++it ) {
KFileListViewItem *item=static_cast<KFileListViewItem *>(it.current());
item->setPixmap( 0, item->fileInfo()->pixmap(KIcon::SizeSmall) );
}
}
void KFileDetailView::updateView( const KFileItem *i )
{
if ( !i )
return;
KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
if ( !item )
return;
item->init();
setSortingKey( item, i );
//item->repaint(); // only repaints if visible
}
void KFileDetailView::setSortingKey( KFileListViewItem *item,
const KFileItem *i )
{
// see also setSorting()
QDir::SortSpec spec = KFileView::sorting();
if ( spec & QDir::Time )
item->setKey( sortingKey( i->time( KIO::UDS_MODIFICATION_TIME ),
i->isDir(), spec ));
else if ( spec & QDir::Size )
item->setKey( sortingKey( i->size(), i->isDir(), spec ));
else // Name or Unsorted
item->setKey( sortingKey( i->text(), i->isDir(), spec ));
}
void KFileDetailView::removeItem( const KFileItem *i )
{
if ( !i )
return;
KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
m_resolver->m_lstPendingMimeIconItems.remove( item );
delete item;
KFileView::removeItem( i );
}
void KFileDetailView::slotSortingChanged( int col )
{
// col is the section here, not the index!
QDir::SortSpec sort = sorting();
int sortSpec = -1;
bool reversed = (col == m_sortingCol) && (sort & QDir::Reversed) == 0;
m_sortingCol = col;
switch( col ) {
case COL_NAME:
sortSpec = (sort & ~QDir::SortByMask | QDir::Name);
break;
case COL_SIZE:
sortSpec = (sort & ~QDir::SortByMask | QDir::Size);
break;
case COL_DATE:
sortSpec = (sort & ~QDir::SortByMask | QDir::Time);
break;
// the following columns have no equivalent in QDir, so we set it
// to QDir::Unsorted and remember the column (m_sortingCol)
case COL_OWNER:
case COL_GROUP:
case COL_PERM:
// grmbl, QDir::Unsorted == SortByMask.
sortSpec = (sort & ~QDir::SortByMask);// | QDir::Unsorted;
break;
default:
break;
}
if ( reversed )
sortSpec |= QDir::Reversed;
else
sortSpec &= ~QDir::Reversed;
if ( sort & QDir::IgnoreCase )
sortSpec |= QDir::IgnoreCase;
else
sortSpec &= ~QDir::IgnoreCase;
KFileView::setSorting( static_cast<QDir::SortSpec>( sortSpec ) );
KFileItem *item;
KFileItemListIterator it( *items() );
if ( sortSpec & QDir::Time ) {
for ( ; (item = it.current()); ++it )
viewItem(item)->setKey( sortingKey( item->time( KIO::UDS_MODIFICATION_TIME ), item->isDir(), sortSpec ));
}
else if ( sortSpec & QDir::Size ) {
for ( ; (item = it.current()); ++it )
viewItem(item)->setKey( sortingKey( item->size(), item->isDir(),
sortSpec ));
}
else { // Name or Unsorted -> use column text
for ( ; (item = it.current()); ++it ) {
KFileListViewItem *i = viewItem( item );
i->setKey( sortingKey( i->text(m_sortingCol), item->isDir(),
sortSpec ));
}
}
KListView::setSorting( m_sortingCol, !reversed );
KListView::sort();
if ( !m_blockSortingSignal )
sig->changeSorting( static_cast<QDir::SortSpec>( sortSpec ) );
}
void KFileDetailView::setSorting( QDir::SortSpec spec )
{
int col = 0;
if ( spec & QDir::Time )
col = COL_DATE;
else if ( spec & QDir::Size )
col = COL_SIZE;
else if ( spec & QDir::Unsorted )
col = m_sortingCol;
else
col = COL_NAME;
// inversed, because slotSortingChanged will reverse it
if ( spec & QDir::Reversed )
spec = (QDir::SortSpec) (spec & ~QDir::Reversed);
else
spec = (QDir::SortSpec) (spec | QDir::Reversed);
m_sortingCol = col;
KFileView::setSorting( (QDir::SortSpec) spec );
// don't emit sortingChanged() when called via setSorting()
m_blockSortingSignal = true; // can't use blockSignals()
slotSortingChanged( col );
m_blockSortingSignal = false;
}
void KFileDetailView::ensureItemVisible( const KFileItem *i )
{
if ( !i )
return;
KFileListViewItem *item = (KFileListViewItem*) i->extraData( this );
if ( item )
KListView::ensureItemVisible( item );
}
// we're in multiselection mode
void KFileDetailView::slotSelectionChanged()
{
sig->highlightFile( 0L );
}
KFileItem * KFileDetailView::firstFileItem() const
{
KFileListViewItem *item = static_cast<KFileListViewItem*>( firstChild() );
if ( item )
return item->fileInfo();
return 0L;
}
KFileItem * KFileDetailView::nextItem( const KFileItem *fileItem ) const
{
if ( fileItem ) {
KFileListViewItem *item = viewItem( fileItem );
if ( item && item->itemBelow() )
return ((KFileListViewItem*) item->itemBelow())->fileInfo();
else
return 0L;
}
else
return firstFileItem();
}
KFileItem * KFileDetailView::prevItem( const KFileItem *fileItem ) const
{
if ( fileItem ) {
KFileListViewItem *item = viewItem( fileItem );
if ( item && item->itemAbove() )
return ((KFileListViewItem*) item->itemAbove())->fileInfo();
else
return 0L;
}
else
return firstFileItem();
}
void KFileDetailView::keyPressEvent( QKeyEvent *e )
{
KListView::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 KFileDetailView::mimeTypeDeterminationFinished()
{
// anything to do?
}
void KFileDetailView::determineIcon( KFileListViewItem *item )
{
(void) item->fileInfo()->determineMimeType();
updateView( item->fileInfo() );
}
void KFileDetailView::listingCompleted()
{
m_resolver->start();
}
QDragObject *KFileDetailView::dragObject()
{
// create a list of the URL:s that we want to drag
KURL::List urls;
KFileItemListIterator it( * KFileView::selectedItems() );
for ( ; it.current(); ++it ){
urls.append( (*it)->url() );
}
QPixmap pixmap;
if( urls.count() > 1 )
pixmap = DesktopIcon( "kmultiple", KIcon::SizeSmall );
if( pixmap.isNull() )
pixmap = currentFileItem()->pixmap( KIcon::SizeSmall );
QPoint hotspot;
hotspot.setX( pixmap.width() / 2 );
hotspot.setY( pixmap.height() / 2 );
QDragObject* myDragObject = new KURLDrag( urls, widget() );
myDragObject->setPixmap( pixmap, hotspot );
return myDragObject;
}
void KFileDetailView::slotAutoOpen()
{
d->autoOpenTimer.stop();
if( !d->dropItem )
return;
KFileItem *fileItem = d->dropItem->fileInfo();
if (!fileItem)
return;
if( fileItem->isFile() )
return;
if ( fileItem->isDir() || fileItem->isLink())
sig->activate( fileItem );
}
bool KFileDetailView::acceptDrag(QDropEvent* e) const
{
return KURLDrag::canDecode( e ) &&
(e->source()!= const_cast<KFileDetailView*>(this)) &&
( e->action() == QDropEvent::Copy
|| e->action() == QDropEvent::Move
|| e->action() == QDropEvent::Link );
}
void KFileDetailView::contentsDragEnterEvent( QDragEnterEvent *e )
{
if ( ! acceptDrag( e ) ) { // can we decode this ?
e->ignore(); // No
return;
}
e->acceptAction(); // Yes
if ((dropOptions() & AutoOpenDirs) == 0)
return;
KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
if ( item ) { // are we over an item ?
d->dropItem = item;
d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
}
else
{
d->dropItem = 0;
d->autoOpenTimer.stop();
}
}
void KFileDetailView::contentsDragMoveEvent( QDragMoveEvent *e )
{
if ( ! acceptDrag( e ) ) { // can we decode this ?
e->ignore(); // No
return;
}
e->acceptAction(); // Yes
if ((dropOptions() & AutoOpenDirs) == 0)
return;
KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
if ( item ) { // are we over an item ?
if (d->dropItem != item)
{
d->dropItem = item;
d->autoOpenTimer.start( autoOpenDelay() ); // restart timer
}
}
else
{
d->dropItem = 0;
d->autoOpenTimer.stop();
}
}
void KFileDetailView::contentsDragLeaveEvent( QDragLeaveEvent * )
{
d->dropItem = 0;
d->autoOpenTimer.stop();
}
void KFileDetailView::contentsDropEvent( QDropEvent *e )
{
d->dropItem = 0;
d->autoOpenTimer.stop();
if ( ! acceptDrag( e ) ) { // can we decode this ?
e->ignore(); // No
return;
}
e->acceptAction(); // Yes
KFileListViewItem *item = dynamic_cast<KFileListViewItem*>(itemAt( contentsToViewport( e->pos() ) ));
KFileItem * fileItem = 0;
if (item)
fileItem = item->fileInfo();
emit dropped(e, fileItem);
KURL::List urls;
if (KURLDrag::decode( e, urls ) && !urls.isEmpty())
{
emit dropped(e, urls, fileItem ? fileItem->url() : KURL());
sig->dropURLs(fileItem, e, urls);
}
}
void KFileListViewItem::init()
{
KFileListViewItem::setPixmap( COL_NAME, inf->pixmap(KIcon::SizeSmall));
setText( COL_NAME, inf->text() );
setText( COL_SIZE, KGlobal::locale()->formatNumber( inf->size(), 0));
setText( COL_DATE, inf->timeString() );
setText( COL_PERM, inf->permissionsString() );
setText( COL_OWNER, inf->user() );
setText( COL_GROUP, inf->group() );
}
void KFileDetailView::virtual_hook( int id, void* data )
{ KListView::virtual_hook( id, data );
KFileView::virtual_hook( id, data ); }
#include "kfiledetailview.moc"
KFileViewSignaler::activate
void activate(const KFileItem *item)
Call this method when an item is selected (depends on single click / double click configuration)...
Definition: kfileview.h:46
KFileDetailView::isSelected
virtual bool isSelected(const KFileItem *i) const
Definition: kfiledetailview.cpp:286
KFileView::onlyDoubleClickSelectsFiles
bool onlyDoubleClickSelectsFiles() const
Definition: kfileview.h:330
KFileDetailView::invertSelection
virtual void invertSelection()
Inverts the current selection, i.e.
Definition: kfiledetailview.cpp:187
KFileDetailView::ensureItemVisible
void ensureItemVisible(const KFileItem *)
pure virtual function, that should be implemented to make item i visible, i.e.
Definition: kfiledetailview.cpp:454
KFileView::items
const KFileItemList * items() const
Definition: kfileview.cpp:283
KFileDetailView::listingCompleted
virtual void listingCompleted()
This hook is called when all items of the currently listed directory are listed and inserted into the...
Definition: kfiledetailview.cpp:531
KFileViewSignaler::highlightFile
void highlightFile(const KFileItem *i)
emits the highlighted signal for item.
Definition: kfileview.h:56
KFileView::insertItem
virtual void insertItem(KFileItem *i)
The derived view must implement this function to add the file in the widget.
Definition: kfileview.cpp:147
KFileDetailView::setSorting
virtual void setSorting(QDir::SortSpec)
Sets the sorting order of the view.
Definition: kfiledetailview.cpp:426
KFileDetailView::insertItem
virtual void insertItem(KFileItem *i)
The derived view must implement this function to add the file in the widget.
Definition: kfiledetailview.cpp:208
KFileDetailView::currentFileItem
virtual KFileItem * currentFileItem() const
Definition: kfiledetailview.cpp:164
KFileView
This class defines an interface to all file views.
Definition: kfileview.h:98
KFileView::sortingKey
static QString sortingKey(const QString &value, bool isDir, int sortSpec)
This method calculates a QString from the given parameters, that is suitable for sorting with e...
Definition: kfileview.cpp:380
KFileDetailView::selectAll
virtual void selectAll()
Selects all items.
Definition: kfiledetailview.cpp:178
KFileView::selectedItems
const KFileItemList * selectedItems() const
Definition: kfileview.cpp:296
KFileDetailView::clearView
virtual void clearView()
pure virtual function, that should be implemented to clear the view.
Definition: kfiledetailview.cpp:202
KFileDetailView::setCurrentItem
virtual void setCurrentItem(const KFileItem *)
Reimplement this to set item the current item in the view, e.g.
Definition: kfiledetailview.cpp:155
KFileDetailView::clearSelection
virtual void clearSelection()
Clears any selection, unhighlights everything.
Definition: kfiledetailview.cpp:173
KFileView::sorting
QDir::SortSpec sorting() const
Returns the sorting order of the internal list.
Definition: kfileview.h:177
KFileView::setSorting
virtual void setSorting(QDir::SortSpec sort)
Sets the sorting order of the view.
Definition: kfileview.cpp:151
KFileView::dropOptions
int dropOptions()
Returns the DND options in effect.
Definition: kfileview.cpp:407
KFileDetailView::widget
virtual QWidget * widget()
a pure virtual function to get a QWidget, that can be added to other widgets.
Definition: kfiledetailview.h:117
KFileView::removeItem
virtual void removeItem(const KFileItem *item)
Removes an item from the list; has to be implemented by the view.
Definition: kfileview.cpp:346
KFileDetailView::setSelected
virtual void setSelected(const KFileItem *, bool)
Tells the view that it should highlight the item.
Definition: kfiledetailview.cpp:143
KFileDetailView::dropped
void dropped(QDropEvent *event, KFileItem *fileItem)
The user dropped something.
KFileDetailView::updateView
virtual void updateView(bool)
does a repaint of the view.
Definition: kfiledetailview.cpp:296
KFileListViewItem::init
void init()
Definition: kfiledetailview.cpp:669
KFileListViewItem
An item for the listiew, that has a reference to its corresponding KFileItem.
Definition: kfiledetailview.h:37
KFileDetailView::removeItem
virtual void removeItem(const KFileItem *)
Removes an item from the list; has to be implemented by the view.
Definition: kfiledetailview.cpp:340
KFileListViewItem::fileInfo
KFileItem * fileInfo() const
Definition: kfiledetailview.h:69
KFileDetailView
A list-view capable of showing KFileItem'.
Definition: kfiledetailview.h:109

KDE Home | KDE Accessibility Home | Description of Access Keys