您最多能選擇 25 個主題 主題必須以字母或數字為開頭,可包含連接號「-」且最長為 35 個字元。
krename/krename/kmylistbox.cpp

841 行
22 KiB

/***************************************************************************
kmylistbox.cpp - description
-------------------
begin : Tue Oct 16 2001
copyright : (C) 2001 by Dominik Seichter
email : domseichter@web.de
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
// QT includes
#include <tqcursor.h>
#include <tqdir.h>
#include <tqdragobject.h>
#include <tqpainter.h>
#include <tqpalette.h>
#include <tqregexp.h>
// KDE includes
#include <tdeapplication.h>
#include <kdirlister.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tdeio/previewjob.h>
#include <tdeio/netaccess.h>
#include <tqptrlist.h>
#include <kurldrag.h>
#include <kurllabel.h>
#include <kpixmap.h>
#include <kpixmapeffect.h>
// Own includes
#include "kmylistbox.h"
#include "krecursivelister.h"
#include "threadedlister.h"
using namespace TDEIO;
KMyListBox::KMyListBox(TQWidget* parent, const char* name, WFlags fl)
:TDEListBox(parent, name, fl)
{
m_running_lister_counter = 0;
drag = ctrlPressed = shiftPressed = mousePressed = false;
moving = false;
m_sorting = UNSORTED;
label = new KURLLabel( TQString(), "<br>" + i18n("Please add some files...") + "<br>", this );
label->setFrameStyle( TQFrame::GroupBoxPanel | TQFrame::Sunken );
setAcceptDrops( true );
setSelectionMode(Extended); // was extended before 2.9.0
connect( this, TQ_SIGNAL(doubleClicked(TQListBoxItem*)), this, TQ_SLOT(openFile(TQListBoxItem*)));
connect( this, TQ_SIGNAL(returnPressed(TQListBoxItem*)), this, TQ_SLOT(openFile(TQListBoxItem*)));
connect( label, TQ_SIGNAL( leftClickedURL() ), this, TQ_SIGNAL( addFiles() ) );
positionLabel();
}
KMyListBox::~KMyListBox()
{
}
KURL KMyListBox::url( int index ) const
{
return static_cast<KMyListBoxItem*>( item( index ) )->url();
}
bool KMyListBox::dir( int index ) const
{
return static_cast<KMyListBoxItem*>( item( index ) )->dir();
}
void KMyListBox::setPreviewSize( int size )
{
previewSize = size;
}
void KMyListBox::removeItem( int index )
{
TDEListBox::removeItem( index );
}
void KMyListBox::addFile( const KURL & filename, bool isfile )
{
// Check if the URL is a file and no dir
// Is the file already in our list ?
if( !isfile && !isFile( filename ) )
return;
if( isInList( filename ) )
return;
insertItem( new KMyListBoxItem( filename, false ), -1 );
positionLabel();
}
void KMyListBox::addDirName( const KURL & dirname )
{
if(!isInList( dirname ) )
{
insertItem( new KMyListBoxItem( dirname, true ), -1 );
positionLabel();
}
}
bool KMyListBox::isFile( const KURL & f, bool autoadd )
{
UDSEntry entry;
NetAccess::stat(f, entry, 0);
KFileItem file( entry, f );
if( !file.isReadable() )
return false;
if( file.isDir() ) {
if( autoadd )
addDir( f, "*", false, true );
return false;
}
return true;
}
void KMyListBox::addDir( const KURL & dirname, const TQString & filter, bool hidden, bool recursively, bool dirnames )
{
ThreadedLister* thl = new ThreadedLister( &m_add_mutex, &m_running_lister_counter, this );
thl->setDirname( dirname );
thl->setDirnames( dirnames );
thl->setFilter( filter );
thl->setHidden( hidden );
thl->setRecursive( recursively );
TDEApplication::setOverrideCursor( TQt::waitCursor );
thl->start();
}
void KMyListBox::addDirName( const KURL & dirname, const TQString & filter, bool hidden, bool recursive )
{
TDEApplication::setOverrideCursor( TQt::waitCursor );
if( recursive ) {
ThreadedLister* thl = new ThreadedLister( &m_add_mutex, &m_running_lister_counter, this );
thl->setDirname( dirname );
thl->setDirnames( true );
thl->setFilter( filter );
thl->setHidden( hidden );
thl->setRecursive( recursive );
thl->setRecursiveDirOnlyMode( true );
thl->start();
} else {
// escape hiden directories
TQString name = dirname.fileName();
if( !hidden && name.right( 1 ) != TQString::fromLatin1(".") )
if( !isInList( dirname ) )
addDirName( dirname );
listerDone( NULL );
}
}
void KMyListBox::dropEvent(TQDropEvent* e)
{
if( e->source() != this )
e->accept(TQTextDrag::canDecode(e));
KURL::List list;
if( KURLDrag::decode( e, list ) )
{
TDEApplication::setOverrideCursor( TQt::waitCursor );
setUpdatesEnabled( false );
for( unsigned int i = 0; i < list.count(); i++ )
addFile( list[i], false );
setUpdatesEnabled( true );
listerDone( NULL );
}
}
void KMyListBox::dragEnterEvent(TQDragEnterEvent* e)
{
if( e->source() != this )
e->accept(TQTextDrag::canDecode(e));
}
void KMyListBox::viewportMousePressEvent( TQMouseEvent* e )
{
if( moving )
move( index( itemAt( e->pos() ) ) );
else {
TDEListBox::viewportMousePressEvent( e );
TQPoint p( e->pos() );
TQListBoxItem *i = itemAt( p );
if ( i ) {
presspos = e->pos();
mousePressed = TRUE;
}
}
}
void KMyListBox::viewportMouseMoveEvent( TQMouseEvent* e )
{
if ( mousePressed && ( presspos - e->pos() ).manhattanLength() > TDEApplication::startDragDistance() ) {
mousePressed = FALSE;
TQListBoxItem *item = itemAt( presspos );
if ( item ) {
TQStringList source = text( index( item ) );
for( int i = 0; i < (signed int)count(); i++ )
if( isSelected(i) && (i != index(item) ))
source.append( text(i) );
TQUriDrag* ud = new TQUriDrag(viewport());
ud->setUnicodeUris( source );
ud->drag();
}
} else
TDEListBox::viewportMouseMoveEvent( e );
}
void KMyListBox::viewportMouseReleaseEvent( TQMouseEvent* e )
{
mousePressed = FALSE;
TDEListBox::viewportMouseReleaseEvent( e );
}
void KMyListBox::keyPressEvent( TQKeyEvent* e )
{
/*
* TODO: Document all this keyboard commands
*/
if( e->key() == Key_Control )
ctrlPressed = true;
else if( e->key() == Key_Shift )
shiftPressed = true;
else if( e->key() == Key_Up )
setCurrentItem( currentItem()-1 );
else if( e->key() == Key_Down )
setCurrentItem( currentItem()+1 );
else if( e->key() == Key_Space )
select( item(currentItem()) );
else if( e->key() == Key_Return )
openFile( item(currentItem()) );
else if( e->key() == Key_Delete )
emit deletePressed();
else if( e->key() == Key_A )
for( unsigned int i = 0; i < count(); i++ )
setSelected( i, true );
else if( e->key() == Key_M ) {
moveMode();
return;
} else if( e->key() == Key_N )
for( unsigned int i = 0; i < count(); i++ )
setSelected( i, false );
else if( e->key() == Key_End )
setCurrentItem( count()-1 );
else if( e->key() == Key_Home )
setCurrentItem( 0 );
else
e->ignore();
emit updateCount();
setPreview( KMyListBoxItem::preview() );
emit updatePreview();
}
void KMyListBox::keyReleaseEvent( TQKeyEvent* e )
{
if( e->key() == Key_Control )
ctrlPressed = false;
else if( e->key() == Key_Shift )
shiftPressed = false;
}
void KMyListBox::openFile( TQListBoxItem* item )
{
if( item ) {
KMyListBoxItem* it = static_cast<KMyListBoxItem*>(item);
KFileItem* fileItem = new KFileItem( KFileItem::Unknown, KFileItem::Unknown, it->url() );
fileItem->run();
delete fileItem;
}
}
void KMyListBox::moveMode()
{
if ( !moving ) {
moving = true;
TDEApplication::setOverrideCursor( TQt::sizeAllCursor );
}
}
void KMyListBox::select( TQListBoxItem* item )
{
if( !ctrlPressed && !shiftPressed )
/* Single click on the list box,
* make all items but the clicked
* one not selected */
for( int i = 0; i < (signed int)count(); i++ )
if( i != index(item) )
setSelected( i, false );
if( shiftPressed ) {
if( currentItem() == -1 ) {
setSelected( item, !isSelected( item ));
setCurrentItem( item );
return;
}
if( currentItem() > index(item) ) {
for( int i = index(item); i <= currentItem(); i++ )
setSelected( i, !isSelected( i ));
setCurrentItem( item );
} else if( currentItem() < index(item) ) { /* Works !*/
for( int i = currentItem()+1; i <= index(item); i++ )
setSelected( i, !isSelected( i ));
} else /* c == index(item) */ /* Works !*/
setSelected( item, !isSelected( item ));
} else {
setSelected( item, !isSelected( item ));
setCurrentItem( item );
}
}
void KMyListBox::preview( KURL::List list )
{
TDEIO::PreviewJob* job = TDEIO::filePreview( list, previewSize, previewSize, 0, 100, false, true, 0 );
connect( job, TQ_SIGNAL( gotPreview( const KFileItem*, const TQPixmap &) ), this, TQ_SLOT( previewDone( const KFileItem*, const TQPixmap &) ) );
connect( job, TQ_SIGNAL( failed( const KFileItem*)), this, TQ_SLOT( previewFailed( const KFileItem* ) ));
connect( job, TQ_SIGNAL( result( TDEIO::Job * ) ), this, TQ_SLOT( previewFinished() ) );
TDEApplication::setOverrideCursor( TQt::waitCursor );
}
void KMyListBox::previewDone( const KFileItem* item, const TQPixmap &pixmap )
{
for( unsigned int i = 0; i < count(); i++ )
if( url( i ) == item->url() ) {
KMyListBoxItem* it = static_cast<KMyListBoxItem*>(this->item( i ));
if( it && !pixmap.isNull() ) {
it->setPixmap( pixmap );
//updateItem( i );
}
break;
}
}
void KMyListBox::previewFailed( const KFileItem* item )
{
for( unsigned int i = 0; i < count(); i++ )
if( url( i ) == item->url() ) {
KMyListBoxItem* it = static_cast<KMyListBoxItem*>(this->item( i ));
if( it ) {
it->setPixmap( item->pixmap( getPreviewSize(), TDEIcon::DefaultState ) );
}
break;
}
}
void KMyListBox::previewFinished()
{
triggerUpdate( true ); //maybe false is enough
TDEApplication::restoreOverrideCursor();
}
void KMyListBox::setPreview( bool prv )
{
KMyListBoxItem::setPreview( prv );
if( prv ) {
KURL::List list;
for( unsigned int i = 0; i < count(); i++ ) {
KMyListBoxItem* it = static_cast<KMyListBoxItem*>(item( i ) );
if( !it->hasPreview() )
list.append( it->url() );
}
preview( list );
}
}
void KMyListBox::setName( bool name )
{
KMyListBoxItem::setName( name );
setPreview( KMyListBoxItem::preview() );
if( name ) {
setColumnMode( FixedNumber );
} else {
setColumnMode( FitToWidth );
}
}
void KMyListBox::move( int i )
{
TDEApplication::restoreOverrideCursor();
moving = false;
if( !count() )
return;
int nbSelectedBefore = 0;
for( unsigned int j = 0 ; j < count() ; j++ ) {
if( isSelected( j ) ) {
if( j < (unsigned int)i )
nbSelectedBefore++;
KMyListBoxItem* item = new KMyListBoxItem( static_cast<KMyListBoxItem*>(this->item( j )) );
removeItem( j );
j--;
insertItem( item, i - nbSelectedBefore );
}
}
}
void KMyListBox::moveUp()
{
if( count() == 0 )
return;
unsigned int i = 0;
setUpdatesEnabled( false );
do {
if( isSelected( i ) && i ) {
moveUp( i );
setSelected( i-1, true );
setCurrentItem( i-1 );
}
i++;
} while( i < count() );
setUpdatesEnabled( true );
}
void KMyListBox::moveUp( int i )
{
if( count() == 0 )
return;
KMyListBoxItem* item = new KMyListBoxItem( static_cast<KMyListBoxItem*>(this->item( i )) );
removeItem( i );
insertItem( item, i - 1 );
}
void KMyListBox::moveDown()
{
if( count() == 0 )
return;
unsigned int i = count();
setUpdatesEnabled( false );
do {
i--;
if( isSelected( i ) && (i < count()) ) {
moveDown( i );
setSelected( i+1, true );
setCurrentItem( i+1 );
}
} while( i > 0 );
setUpdatesEnabled( true );
}
void KMyListBox::moveDown( int i )
{
if( count() == 0 )
return;
KMyListBoxItem* item = new KMyListBoxItem( static_cast<KMyListBoxItem*>(this->item( i )) );
removeItem( i );
insertItem( item, i + 1 );
}
bool KMyListBox::isInList( KURL text )
{
// TODO: faster find algorithm
for( unsigned int i = 0; i < count(); i++ ) {
KMyListBoxItem* it = dynamic_cast<KMyListBoxItem*>(item( i ) );
if( it && it->url() == text ) {
return true;
}
}
return false;
}
void KMyListBox::customEvent( TQCustomEvent* e )
{
if( e->type() == ThreadedLister::TYPE() )
{
listerDone( (ThreadedLister*)e->data() );
}
}
void KMyListBox::listerDone( ThreadedLister* lister )
{
m_add_mutex.lock();
if( lister )
delete lister;
TDEApplication::restoreOverrideCursor();
setUpdatesEnabled( false );
setPreview( KMyListBoxItem::preview() );
sortList();
setUpdatesEnabled( true );
emit updateCount();
emit updatePreview();
m_add_mutex.unlock();
}
unsigned int KMyListBox::runningAddListeners()
{
unsigned int u;
m_add_mutex.lock();
u = m_running_lister_counter;
m_add_mutex.unlock();
return u;
}
void KMyListBox::sortAscending()
{
m_sorting = ASCENDING;
sortList();
}
void KMyListBox::sortDescending()
{
m_sorting = DESCENDING;
sortList();
}
void KMyListBox::sortRandom()
{
m_sorting = RANDOM;
sortList();
}
void KMyListBox::sortUnsorted()
{
m_sorting = UNSORTED;
sortList();
}
void KMyListBox::sortNummeric()
{
m_sorting = NUMMERIC;
sortList();
}
void KMyListBox::sortList()
{
TDEApplication::setOverrideCursor( TQt::WaitCursor );
if( m_sorting == ASCENDING )
sort( true );
else if( m_sorting == DESCENDING )
sort( false );
else if( m_sorting == RANDOM )
{
unsigned int p = 0;
for( unsigned int i = 0;i<count();i++)
{
p = TDEApplication::random() % count();
if( p != i ) // This prevents the creation of a new ListBoxItem
// on the same position as before. It would not change
// the position of item, but cost a little bit of speed
{
KMyListBoxItem* item = new KMyListBoxItem( static_cast<KMyListBoxItem*>(this->item( i )) );
removeItem( i );
insertItem( item, p );
}
}
}
else if( m_sorting == NUMMERIC )
{
// a very simple bubble sort which sorts filenames by a number inside them.
// if no number is found a lexical comparison is performed
unsigned int z = count();
while( z-- )
for( unsigned int i=1;i<=z;i++)
{
KURL url1 = url( i - 1 );
KURL url2 = url( i );
if( url1.directory() != url2.directory() )
{
// different directory, do a lexical comparison
if( text( i - 1 ).compare( text( i ) ) >= 0 )
moveDown( i - 1 );
}
else
{
if( compareNummeric( url1.filename(), url2.filename() ) >= 0 )
moveDown( i - 1 );
}
}
}
TDEApplication::restoreOverrideCursor();
}
void KMyListBox::setSorting( int s )
{
switch( s )
{
default:
case UNSORTED:
sortUnsorted();
break;
case ASCENDING:
sortAscending();
break;
case DESCENDING:
sortDescending();
break;
case RANDOM:
sortRandom();
break;
case NUMMERIC:
sortNummeric();
break;
}
emit updatePreview();
}
int KMyListBox::compareNummeric( const TQString & s1, const TQString & s2 )
{
unsigned int z = 0;
unsigned int max = ( s1.length() > s2.length() ? s1.length() : s2.length() );
TQString num1;
TQString num2;
for( z=0;z<max;z++)
{
//if( z >= s1.length() || z >= s2.length() )
// break;
if( s1[z] != s2[z] )
{
if( z < s1.length() && s1[z].isDigit() )
num1 = findNumInString( z, s1 );
if( z < s2.length() && s2[z].isDigit() )
num2 = findNumInString( z, s2 );
if( num1.isNull() && num2.isNull() )
break;
int a = num1.toInt();
int b = num2.toInt();
if( a == b )
return s1.compare( s2 );
else
return ( a > b ) ? 1 : -1;
}
}
return s1.compare( s2 );
}
const TQString KMyListBox::findNumInString( unsigned int pos, const TQString & s )
{
TQString num;
for( int i = (int)pos; i >= 0; i-- )
if( s[i].isDigit() )
num.prepend( s[i] );
else
break;
for( unsigned int i = pos + 1; i < s.length(); i++ )
if( s[i].isDigit() )
num.append( s[i] );
else
break;
return num;
}
void KMyListBox::resizeEvent( TQResizeEvent* e )
{
TDEListBox::resizeEvent( e );
positionLabel();
}
void KMyListBox::clear()
{
TDEListBox::clear();
positionLabel();
}
void KMyListBox::positionLabel()
{
if( count() )
{
label->hide();
}
else
{
int x = (width() - label->minimumSizeHint().width()) / 2;
int y = (height() - label->minimumSizeHint().height()) / 2;
label->setGeometry( x, y, label->minimumSizeHint().width(), label->minimumSizeHint().height() );
label->show();
}
}
void KMyListBox::paintEvent( TQPaintEvent* e )
{
// tqDebug("Updates=%i", (int)isUpdatesEnabled() );
//if( isUpdatesEnabled() )
TDEListBox::paintEvent( e );
}
KMyListBoxItem::KMyListBoxItem( const KMyListBoxItem* item )
: TQListBoxItem()
{
m_url = item->url();
m_dir = item->dir();
m_has_preview = false;
pm = *item->pixmap();
}
KMyListBoxItem::KMyListBoxItem( const KURL & u, bool b )
: TQListBoxItem()
{
m_url = u;
m_dir = b;
m_has_preview = false;
}
void KMyListBoxItem::setPixmap( const TQPixmap & pix )
{
KMyListBox* box = static_cast<KMyListBox*>(this->listBox());
pm.resize( box->getPreviewSize(), box->getPreviewSize() );
pm.fill( box->colorGroup().base() );
TQPainter painter( &pm );
painter.drawPixmap( (pm.width()-pix.width())/2, (pm.height()-pix.height())/2, pix );
m_has_preview = true;
}
void KMyListBoxItem::setName( bool b )
{
KMyListBoxItem::m_name = b;
}
void KMyListBoxItem::setPreview( bool b )
{
KMyListBoxItem::m_preview = b;
}
void KMyListBoxItem::paint( TQPainter *painter )
{
if( !KMyListBoxItem::m_preview ) {
int itemHeight = height( listBox() );
TQFontMetrics fm = painter->fontMetrics();
int yPos = ( ( itemHeight - fm.height() ) / 2 ) + fm.ascent();
painter->drawText( 3, yPos, text() );
} else {
int itemHeight = height( listBox() );
int yPos;
if( pm.isNull() ) {
KFileItem item( KFileItem::Unknown, KFileItem::Unknown, m_url );
KMyListBox* box = static_cast<KMyListBox*>(this->listBox());
setPixmap( item.pixmap( box->getPreviewSize(), TDEIcon::DefaultState ) );
}
yPos = ( itemHeight - pm.height() ) / 2;
if( !isSelected() )
painter->drawPixmap( 3, yPos, pm);
else
{
KPixmap pix = KPixmapEffect::selectedPixmap( pm, listBox()->colorGroup().highlight() );
painter->drawPixmap( 3, yPos, pix );
}
if( KMyListBoxItem::m_name && !m_url.isEmpty() ) {
TQFontMetrics fm = painter->fontMetrics();
yPos = ( ( itemHeight - fm.height() ) / 2 ) + fm.ascent();
painter->drawText( pm.width() + 5, yPos, text() );
}
}
}
int KMyListBoxItem::height( const TQListBox* lb ) const
{
if( !KMyListBoxItem::m_preview ) {
int h = listBox() ? listBox()->fontMetrics().lineSpacing() + 2 : 0;
return TQMAX( h, TQApplication::globalStrut().height() );
} else {
int h;
if ( KMyListBoxItem::m_name && !m_url.prettyURL().isEmpty() )
h = pm.height();
else
h = TQMAX( pm.height(), lb->fontMetrics().lineSpacing() + 2 );
return TQMAX( h, TQApplication::globalStrut().height() );
}
}
int KMyListBoxItem::width( const TQListBox* ) const
{
if( !KMyListBoxItem::m_preview ) {
int w = listBox() ? listBox()->fontMetrics().width( text() ) + 6 : 0;
return TQMAX( w, TQApplication::globalStrut().width() );
} else {
if ( m_url.path().isEmpty() || !KMyListBoxItem::m_name)
return TQMAX( pm.width() + 6, TQApplication::globalStrut().width() );
return TQMAX( pm.width() + listBox()->fontMetrics().width( text() ) + 6, TQApplication::globalStrut().width() );
}
}
TQString KMyListBoxItem::text() const
{
return m_url.prettyURL( 0, m_url.isLocalFile() ? KURL::StripFileProtocol : KURL::NoAdjustements );
}
bool KMyListBoxItem::m_preview = false;
bool KMyListBoxItem::m_name = false;
#include "kmylistbox.moc"