/*************************************************************************** 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 #include #include #include #include #include // KDE includes #include #include #include #include #include #include #include #include #include #include #include // 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(), "
" + i18n("Please add some files...") + "
", this ); label->setFrameStyle( TQFrame::GroupBoxPanel | TQFrame::Sunken ); setAcceptDrops( true ); setSelectionMode(Extended); // was extended before 2.9.0 connect( this, TQT_SIGNAL(doubleClicked(TQListBoxItem*)), this, TQT_SLOT(openFile(TQListBoxItem*))); connect( this, TQT_SIGNAL(returnPressed(TQListBoxItem*)), this, TQT_SLOT(openFile(TQListBoxItem*))); connect( label, TQT_SIGNAL( leftClickedURL() ), this, TQT_SIGNAL( addFiles() ) ); positionLabel(); } KMyListBox::~KMyListBox() { } KURL KMyListBox::url( int index ) const { return static_cast( item( index ) )->url(); } bool KMyListBox::dir( int index ) const { return static_cast( 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(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, TQT_SIGNAL( gotPreview( const KFileItem*, const TQPixmap &) ), this, TQT_SLOT( previewDone( const KFileItem*, const TQPixmap &) ) ); connect( job, TQT_SIGNAL( failed( const KFileItem*)), this, TQT_SLOT( previewFailed( const KFileItem* ) )); connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_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(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(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(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(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(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(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(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(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= 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(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(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"