/* ark -- archiver for the KDE project Copyright (C) 2005: Henrique Pinto <henrique.pinto@kdemail.net> 2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de> 2001: Corel Corporation (author: Michael Jarrett, michaelj@corel.com) 1999-2000: Corel Corporation (author: Emily Ezust, emilye@corel.com) 1999: Francois-Xavier Duranceau duranceau@kde.org 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. */ // TQt includes #include <tqpainter.h> #include <tqwhatsthis.h> #include <tqheader.h> // KDE includes #include <tdelocale.h> #include <tdeglobal.h> #include <kdebug.h> #include <tdeglobalsettings.h> #include <kmimetype.h> #include "filelistview.h" #include "arch.h" ///////////////////////////////////////////////////////////////////// // FileLVI implementation ///////////////////////////////////////////////////////////////////// FileLVI::FileLVI( TDEListView* lv ) : TDEListViewItem( lv ), m_fileSize( 0 ), m_packedFileSize( 0 ), m_ratio( 0 ), m_timeStamp( TQDateTime() ), m_entryName( TQString() ) { } FileLVI::FileLVI( TDEListViewItem* lvi ) : TDEListViewItem( lvi ), m_fileSize( 0 ), m_packedFileSize( 0 ), m_ratio( 0 ), m_timeStamp( TQDateTime() ), m_entryName( TQString() ) { } TQString FileLVI::key( int column, bool ascending ) const { if ( column == 0 ) return fileName(); else return TQListViewItem::key( column, ascending ); } int FileLVI::compare( TQListViewItem * i, int column, bool ascending ) const { FileLVI * item = static_cast< FileLVI * >( i ); if ( ( this->childCount() > 0 ) && ( item->childCount() == 0 ) ) return -1; if ( ( this->childCount() == 0 ) && ( item->childCount() > 0 ) ) return 1; if ( column == 0 ) return TDEListViewItem::compare( i, column, ascending ); columnName colName = ( static_cast< FileListView * > ( listView() ) )->nameOfColumn( column ); switch ( colName ) { case sizeCol: { return ( m_fileSize < item->fileSize() ? -1 : ( m_fileSize > item->fileSize() ? 1 : 0 ) ); break; } case ratioStrCol: { return ( m_ratio < item->ratio() ? -1 : ( m_ratio > item->ratio() ? 1 : 0 ) ); break; } case packedStrCol: { return ( m_packedFileSize < item->packedFileSize() ? -1 : ( m_packedFileSize > item->packedFileSize() ? 1 : 0 ) ); break; } case timeStampStrCol: { return ( m_timeStamp < item->timeStamp() ? -1 : ( m_timeStamp > item->timeStamp() ? 1 : 0 ) ); break; } default: return TDEListViewItem::compare( i, column, ascending ); } } void FileLVI::setText( int column, const TQString &text ) { columnName colName = ( static_cast< FileListView * > ( listView() ) )->nameOfColumn( column ); if ( column == 0 ) { TQString name = text; if ( name.endsWith( "/" ) ) name = name.left( name.length() - 1 ); if ( name.startsWith( "/" ) ) name = name.mid( 1 ); int pos = name.findRev( '/' ); if ( pos != -1 ) name = name.right( name.length() - pos - 1 ); TQListViewItem::setText( column, name ); m_entryName = text; } else if ( colName == sizeCol ) { m_fileSize = text.toULongLong(); TQListViewItem::setText( column, TDEIO::convertSize( m_fileSize ) ); } else if ( colName == packedStrCol ) { m_packedFileSize = text.toULongLong(); TQListViewItem::setText( column, TDEIO::convertSize( m_packedFileSize ) ); } else if ( colName == ratioStrCol ) { int l = text.length() - 1; if ( l>0 && text[l] == '%' ) m_ratio = text.left(l).toDouble(); else m_ratio = text.toDouble(); TQListViewItem::setText( column, i18n( "Packed Ratio", "%1 %" ) .arg(TDEGlobal::locale()->formatNumber( m_ratio, 1 ) ) ); } else if ( colName == timeStampStrCol ) { if ( text.isEmpty() ) TQListViewItem::setText(column, text); else { m_timeStamp = TQDateTime::fromString( text, TQt::ISODate ); TQListViewItem::setText( column, TDEGlobal::locale()->formatDateTime( m_timeStamp ) ); } } else TQListViewItem::setText(column, text); } void FileLVI::setItemData( const TQStringList &entryData ) { int i = 0; for (TQStringList::ConstIterator it = entryData.begin(); it != entryData.end(); ++it) { this->setText(i, *it); ++i; } } static FileLVI* folderLVI( TDEListViewItem *parent, const TQString& name ) { FileLVI *folder = new FileLVI( parent ); folder->setText( 0, name ); folder->setPixmap( 0, KMimeType::mimeType( "inode/directory" )->pixmap( TDEIcon::Small ) ); return folder; } static FileLVI* folderLVI( TDEListView *parent, const TQString& name ) { FileLVI *folder = new FileLVI( parent ); folder->setText( 0, name ); folder->setPixmap( 0, KMimeType::mimeType( "inode/directory" )->pixmap( TDEIcon::Small ) ); return folder; } ///////////////////////////////////////////////////////////////////// // FileListView implementation ///////////////////////////////////////////////////////////////////// FileListView::FileListView(TQWidget *parent, const char* name) : TDEListView(parent, name) { TQWhatsThis::add( this, i18n( "This area is for displaying information about the files contained within an archive." ) ); setMultiSelection( true ); setSelectionModeExt( FileManager ); setItemsMovable( false ); setRootIsDecorated( true ); setShowSortIndicator( true ); setItemMargin( 3 ); header()->hide(); // Don't show the header until there is something to be shown in it m_pressed = false; } int FileListView::addColumn ( const TQString & label, int width ) { int index = TDEListView::addColumn( label, width ); if ( label == SIZE_COLUMN.first ) { m_columnMap[ index ] = sizeCol; } else if ( label == PACKED_COLUMN.first ) { m_columnMap[ index ] = packedStrCol; } else if ( label == RATIO_COLUMN.first ) { m_columnMap[ index ] = ratioStrCol; } else if ( label == TIMESTAMP_COLUMN.first ) { m_columnMap[ index ] = timeStampStrCol; } else { m_columnMap[ index ] = otherCol; } return index; } void FileListView::removeColumn( int index ) { for ( unsigned int i = index; i < m_columnMap.count() - 2; i++ ) { m_columnMap.replace( i, m_columnMap[ i + 1 ] ); } m_columnMap.remove( m_columnMap[ m_columnMap.count() - 1 ] ); TDEListView::removeColumn( index ); } columnName FileListView::nameOfColumn( int index ) { return m_columnMap[ index ]; } TQStringList FileListView::selectedFilenames() { TQStringList files; FileLVI *item = static_cast<FileLVI*>( firstChild() ); while ( item ) { if ( item->isSelected() ) { // If the item has children, add each child and the item if ( item->childCount() > 0 ) { files += item->fileName(); files += childrenOf( item ); /* If we got here, then the logic for "going to the next item" * is a bit different: as we already dealt with all the children, * the "next item" is the next sibling of the current item, not * its first child. If the current item has no siblings, then * the next item is the next sibling of its parent, and so on. */ FileLVI *nitem = static_cast<FileLVI*>( item->nextSibling() ); while ( !nitem && item->parent() ) { item = static_cast<FileLVI*>( item->parent() ); if ( item->parent() ) nitem = static_cast<FileLVI*>( item->parent()->nextSibling() ); } item = nitem; continue; } else { // If the item has no children, just add it to the list files += item->fileName(); } } // Go to the next item item = static_cast<FileLVI*>( item->itemBelow() ); } return files; } TQStringList FileListView::fileNames() { TQStringList files; TQListViewItemIterator it( this ); while ( it.current() ) { FileLVI *item = static_cast<FileLVI*>( it.current() ); files += item->fileName(); ++it; } return files; } bool FileListView::isSelectionEmpty() { FileLVI * flvi = (FileLVI*)firstChild(); while (flvi) { if( flvi->isSelected() ) return false; else flvi = (FileLVI*)flvi->itemBelow(); } return true; } void FileListView::contentsMousePressEvent(TQMouseEvent *e) { if( e->button()==TQt::LeftButton ) { m_pressed = true; m_presspos = e->pos(); } TDEListView::contentsMousePressEvent(e); } void FileListView::contentsMouseReleaseEvent(TQMouseEvent *e) { m_pressed = false; TDEListView::contentsMouseReleaseEvent(e); } void FileListView::contentsMouseMoveEvent(TQMouseEvent *e) { if(!m_pressed) { TDEListView::contentsMouseMoveEvent(e); } else if( ( m_presspos - e->pos() ).manhattanLength() > TDEGlobalSettings::dndEventDelay() ) { m_pressed = false; // Prevent triggering again if(isSelectionEmpty()) { return; } TQStringList dragFiles = selectedFilenames(); emit startDragRequest( dragFiles ); TDEListView::contentsMouseMoveEvent(e); } } FileLVI* FileListView::item(const TQString& filename) const { if (filename.isEmpty()) { return 0; } TQStringList pathList = TQStringList::split( '/', filename ); FileLVI * flvi = (FileLVI*) firstChild(); // File path iterator TQStringList::ConstIterator pathIt = pathList.begin(), pathEnd = pathList.end(); // Iterate over the current tree level siblings while (flvi) { if (flvi->fileName() == *pathIt) { ++pathIt; if (pathIt != pathEnd) { flvi = (FileLVI*) flvi->firstChild(); } else { return flvi; } } else { flvi = (FileLVI*) flvi->nextSibling(); } } return 0; } FileLVI *FileListView::addItem( const TQStringList & entries ) { FileLVI *flvi, *parent = findParent( entries[0] ); if ( parent ) flvi = new FileLVI( parent ); else flvi = new FileLVI( this ); flvi->setItemData (entries); KMimeType::Ptr mimeType = KMimeType::findByPath( entries.first(), 0, true ); flvi->setPixmap( 0, mimeType->pixmap( TDEIcon::Small ) ); return flvi; } FileLVI *FileListView::addOrUpdateItem( const TQStringList &entries ) { FileLVI *flvi = item ( entries[0] ); if (flvi) { flvi->setItemData (entries); return flvi; } else { return addItem (entries); } } void FileListView::selectAll() { TQListView::selectAll( true ); } void FileListView::unselectAll() { TQListView::selectAll( false ); } void FileListView::setHeaders( const ColumnList& columns ) { clearHeaders(); for ( ColumnList::const_iterator it = columns.constBegin(); it != columns.constEnd(); ++it ) { TQPair< TQString, TQt::AlignmentFlags > pair = *it; int colnum = addColumn( pair.first ); setColumnAlignment( colnum, pair.second ); } setResizeMode( TQListView::LastColumn ); header()->show(); } void FileListView::clearHeaders() { header()->hide(); while ( columns() > 0 ) { removeColumn( 0 ); } } int FileListView::totalFiles() { int numFiles = 0; TQListViewItemIterator it( this ); while ( it.current() ) { if ( it.current()->childCount() == 0 ) ++numFiles; ++it; } return numFiles; } int FileListView::selectedFilesCount() { int numFiles = 0; TQListViewItemIterator it( this, TQListViewItemIterator::Selected ); while ( it.current() ) { ++numFiles; ++it; } return numFiles; } TDEIO::filesize_t FileListView::totalSize() { TDEIO::filesize_t size = 0; TQListViewItemIterator it(this); while ( it.current() ) { FileLVI *item = static_cast<FileLVI*>( it.current() ); size += item->fileSize(); ++it; } return size; } TDEIO::filesize_t FileListView::selectedSize() { TDEIO::filesize_t size = 0; TQListViewItemIterator it( this, TQListViewItemIterator::Selected ); while ( it.current() ) { FileLVI *item = static_cast<FileLVI*>( it.current() ); size += item->fileSize(); ++it; } return size; } FileLVI* FileListView::findParent( const TQString& fullname ) { TQString name = fullname; if ( name.endsWith( "/" ) ) name = name.left( name.length() -1 ); if ( name.startsWith( "/" ) ) name = name.mid( 1 ); // Checks if this entry needs a parent if ( !name.contains( '/' ) ) return static_cast< FileLVI* >( 0 ); // Get a list of ancestors TQString parentFullname = name.left( name.findRev( '/' ) ); TQStringList ancestorList = TQStringList::split( '/', parentFullname ); // Checks if the listview contains the first item in the list of ancestors TQListViewItem *item = firstChild(); while ( item ) { if ( item->text( 0 ) == ancestorList[0] ) break; item = item->nextSibling(); } // If the list view does not contain the item, create it if ( !item ) { item = folderLVI( this, ancestorList[0] ); } // We've already dealt with the first item, remove it ancestorList.pop_front(); while ( ancestorList.count() > 0 ) { TQString name = ancestorList[0]; FileLVI *parent = static_cast< FileLVI*>( item ); item = parent->firstChild(); while ( item ) { if ( item->text(0) == name ) break; item = item->nextSibling(); } if ( !item ) { item = folderLVI( parent, name ); } ancestorList.pop_front(); } item->setOpen( true ); return static_cast< FileLVI* >( item ); } TQStringList FileListView::childrenOf( FileLVI* parent ) { Q_ASSERT( parent ); TQStringList children; FileLVI *item = static_cast<FileLVI*>( parent->firstChild() ); while ( item ) { if ( item->childCount() == 0 ) { children += item->fileName(); } else { children += item->fileName(); children += childrenOf( item ); } item = static_cast<FileLVI*>( item->nextSibling() ); } return children; } #include "filelistview.moc"