• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdeutils
  • Sitemap
  • Contact Us
 

ark

archivemodel.cpp

Go to the documentation of this file.
00001 /*
00002  * ark -- archiver for the KDE project
00003  *
00004  * Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  *
00020  */
00021 #include "archivemodel.h"
00022 #include "kerfuffle/archive.h"
00023 #include "kerfuffle/jobs.h"
00024 
00025 #include <QList>
00026 #include <QPixmap>
00027 
00028 #include <KLocale>
00029 #include <KMimeType>
00030 #include <KIconLoader>
00031 #include <KIO/NetAccess>
00032 
00033 class ArchiveDirNode;
00034 
00035 class ArchiveNode
00036 {
00037     public:
00038         ArchiveNode( ArchiveDirNode *parent, const ArchiveEntry & entry )
00039             : m_parent( parent ), m_row( -1 )
00040         {
00041             setEntry( entry );
00042         }
00043 
00044         virtual ~ArchiveNode() {}
00045 
00046         ArchiveEntry entry() const { return m_entry; }
00047         void setEntry( const ArchiveEntry & entry )
00048         {
00049             m_entry = entry;
00050             QStringList pieces = entry[ FileName ].toString().split( '/', QString::SkipEmptyParts );
00051             m_name = pieces.isEmpty()? QString() : pieces.last();
00052         }
00053 
00054         ArchiveDirNode *parent() const { return m_parent; }
00055 
00056         int row();
00057         QString name() const { return m_name; }
00058 
00059         virtual bool isDir() const { return false; }
00060 
00061         QPixmap icon()
00062         {
00063             if ( m_icon.isNull() )
00064             {
00065                 KMimeType::Ptr mimeType = KMimeType::findByPath( m_entry[ FileName ].toString(), 0, true );
00066                 m_icon = KIconLoader::global()->loadMimeTypeIcon( mimeType->iconName(), KIconLoader::Small );
00067             }
00068             return m_icon;
00069         }
00070 
00071     protected:
00072         QPixmap         m_icon;
00073 
00074     private:
00075         ArchiveEntry    m_entry;
00076         ArchiveDirNode *m_parent;
00077         QString         m_name;
00078         int             m_row;
00079 };
00080 
00081 class ArchiveDirNode: public ArchiveNode
00082 {
00083     public:
00084         ArchiveDirNode( ArchiveDirNode *parent, const ArchiveEntry & entry )
00085             : ArchiveNode( parent, entry )
00086         {
00087             m_icon = KIconLoader::global()->loadMimeTypeIcon( KMimeType::mimeType( "inode/directory" )->iconName(), KIconLoader::Small );
00088         }
00089 
00090         ~ArchiveDirNode()
00091         {
00092             clear();
00093         }
00094 
00095         QList<ArchiveNode*>& entries() { return m_entries; }
00096 
00097         virtual bool isDir() const { return true; }
00098 
00099         ArchiveNode* find( const QString & name )
00100         {
00101             foreach( ArchiveNode *node, m_entries )
00102             {
00103                 if ( node && ( node->name() == name ) )
00104                 {
00105                     return node;
00106                 }
00107             }
00108             return 0;
00109         }
00110 
00111         ArchiveNode* findByPath( const QString & path )
00112         {
00113             QStringList pieces = path.split( '/' );
00114             if ( pieces.isEmpty() )
00115             {
00116                 return 0;
00117             }
00118 
00119             ArchiveNode *next = find( pieces[ 0 ] );
00120 
00121             if ( pieces.count() == 1 )
00122             {
00123                 return next;
00124             }
00125             if ( next->isDir() )
00126                 return static_cast<ArchiveDirNode*>( next )->findByPath( pieces.join( "/" ) );
00127             return 0;
00128         }
00129 
00130         void clear()
00131         {
00132             qDeleteAll( m_entries );
00133             m_entries.clear();
00134         }
00135 
00136     private:
00137         QList<ArchiveNode*> m_entries;
00138 };
00139 
00140 int ArchiveNode::row()
00141 {
00142     if ( m_row != -1 ) return m_row;
00143 
00144     if ( parent() )
00145     {
00146         m_row = parent()->entries().indexOf( const_cast<ArchiveNode*>( this ) );
00147         return m_row;
00148     }
00149     return 0;
00150 }
00151 
00152 ArchiveModel::ArchiveModel( QObject *parent )
00153     : QAbstractItemModel( parent ), m_archive( 0 ),
00154       m_rootNode( new ArchiveDirNode( 0, ArchiveEntry() ) ),
00155       m_jobTracker(0)
00156 {
00157 }
00158 
00159 ArchiveModel::~ArchiveModel()
00160 {
00161     delete m_archive;
00162     m_archive = 0;
00163 
00164     delete m_rootNode;
00165     m_rootNode = 0;
00166 }
00167 
00168 QVariant ArchiveModel::data( const QModelIndex &index, int role ) const
00169 {
00170     if ( index.isValid() )
00171     {
00172         ArchiveNode *node = static_cast<ArchiveNode*>( index.internalPointer() );
00173         switch ( role )
00174         {
00175             case Qt::DisplayRole:
00176                 if ( index.column() == 0 )
00177                 {
00178                     return node->name();
00179                 }
00180                 else
00181                 {
00182                     if ( node->isDir() || node->entry().contains( Link ) )
00183                     {
00184                         return QVariant();
00185                     }
00186                     else
00187                     {
00188                         return KIO::convertSize( node->entry()[ Size ].toULongLong() );
00189                     }
00190                 }
00191             case Qt::DecorationRole:
00192                 if ( index.column() == 0 )
00193                 {
00194                     return node->icon();
00195                 }
00196                 return QVariant();
00197             default:
00198                 return QVariant();
00199         }
00200     }
00201     return QVariant();
00202 }
00203 
00204 Qt::ItemFlags ArchiveModel::flags( const QModelIndex &index ) const
00205 {
00206     if ( index.isValid() )
00207     {
00208         return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
00209     }
00210 
00211     return 0;
00212 }
00213 
00214 QVariant ArchiveModel::headerData( int section, Qt::Orientation, int role ) const
00215 {
00216     if ( role == Qt::DisplayRole )
00217     {
00218         switch ( section )
00219         {
00220             case 0:
00221                 return i18nc( "Name of a file inside an archive", "Name" );
00222             case 1:
00223                 return i18n( "Size" );
00224         }
00225     }
00226     return QVariant();
00227 }
00228 
00229 QModelIndex ArchiveModel::index( int row, int column, const QModelIndex &parent ) const
00230 {
00231     if ( hasIndex( row, column, parent ) )
00232     {
00233         ArchiveDirNode *parentNode = parent.isValid()? static_cast<ArchiveDirNode*>( parent.internalPointer() ) : m_rootNode;
00234 
00235         Q_ASSERT( parentNode->isDir() );
00236 
00237         ArchiveNode *item = parentNode->entries().value( row, 0 );
00238         if ( item )
00239         {
00240             return createIndex( row, column, item );
00241         }
00242     }
00243 
00244     return QModelIndex();
00245 }
00246 
00247 QModelIndex ArchiveModel::parent( const QModelIndex &index ) const
00248 {
00249     if ( index.isValid() )
00250     {
00251         ArchiveNode *item = static_cast<ArchiveNode*>( index.internalPointer() );
00252         Q_ASSERT( item );
00253         if ( item->parent() && ( item->parent() != m_rootNode ) )
00254         {
00255             return createIndex( item->parent()->row(), 0, item->parent() );
00256         }
00257     }
00258     return QModelIndex();
00259 }
00260 
00261 ArchiveEntry ArchiveModel::entryForIndex( const QModelIndex &index )
00262 {
00263     if ( index.isValid() )
00264     {
00265         ArchiveNode *item = static_cast<ArchiveNode*>( index.internalPointer() );
00266         Q_ASSERT( item );
00267         return item->entry();
00268     }
00269     return ArchiveEntry();
00270 }
00271 
00272 int ArchiveModel::childCount( const QModelIndex &index )
00273 {
00274     if ( index.isValid() )
00275     {
00276         ArchiveNode *item = static_cast<ArchiveNode*>( index.internalPointer() );
00277         Q_ASSERT( item );
00278         if ( item->isDir() )
00279         {
00280             return static_cast<ArchiveDirNode*>( item )->entries().count();
00281         }
00282         return 0;
00283     }
00284     return -1;
00285 }
00286 
00287 int ArchiveModel::rowCount( const QModelIndex &parent ) const
00288 {
00289     if ( parent.column() <= 0 )
00290     {
00291         ArchiveNode *parentNode = parent.isValid()? static_cast<ArchiveNode*>( parent.internalPointer() ) : m_rootNode;
00292 
00293         if ( parentNode && parentNode->isDir() )
00294         {
00295             return static_cast<ArchiveDirNode*>( parentNode )->entries().count();
00296         }
00297     }
00298     return 0;
00299 }
00300 
00301 int ArchiveModel::columnCount( const QModelIndex &parent ) const
00302 {
00303     if ( parent.isValid() )
00304     {
00305         return static_cast<ArchiveNode*>( parent.internalPointer() )->entry().size();
00306     }
00307     return 2; // TODO: Completely bogus
00308 }
00309 
00310 ArchiveDirNode* ArchiveModel::parentFor( const ArchiveEntry& entry )
00311 {
00312     QStringList pieces = entry[ FileName ].toString().split( '/', QString::SkipEmptyParts );
00313     pieces.removeLast();
00314 
00315     ArchiveDirNode *parent = m_rootNode;
00316 
00317     foreach( QString piece, pieces )
00318     {
00319         ArchiveNode *node = parent->find( piece );
00320         if ( !node )
00321         {
00322             ArchiveEntry e;
00323             e[ FileName ] = parent->entry()[ FileName ].toString() + '/' + piece;
00324             node = new ArchiveDirNode( parent, e );
00325         }
00326         if ( !node->isDir() )
00327         {
00328             ArchiveEntry e( node->entry() );
00329             int index = parent->entries().indexOf( node );
00330             delete node;
00331             node = new ArchiveDirNode( parent, e );
00332             parent->entries()[ index ] = node;
00333         }
00334         parent = static_cast<ArchiveDirNode*>( node );
00335     }
00336 
00337     return parent;
00338 }
00339 QModelIndex ArchiveModel::indexForNode( ArchiveNode *node )
00340 {
00341     Q_ASSERT( node );
00342     if ( node != m_rootNode )
00343     {
00344         Q_ASSERT( node->parent() );
00345         Q_ASSERT( node->parent()->isDir() );
00346         return createIndex( node->row(), 0, node );
00347     }
00348     return QModelIndex();
00349 }
00350 
00351 void ArchiveModel::slotEntryRemoved( const QString & path )
00352 {
00353     // TODO: Do something
00354     ArchiveNode *entry = m_rootNode->findByPath( path );
00355     if ( entry )
00356     {
00357         ArchiveDirNode *parent = entry->parent();
00358         QModelIndex index = indexForNode( entry );
00359 
00360         beginRemoveRows( indexForNode( parent ), entry->row(), entry->row() );
00361 
00362         delete parent->entries()[ entry->row() ];
00363         parent->entries()[ entry->row() ] = 0;
00364 
00365         endRemoveRows();
00366     }
00367 }
00368 
00369 void ArchiveModel::slotNewEntry( const ArchiveEntry& entry )
00370 {
00372     ArchiveDirNode *parent  = parentFor( entry ); // TODO: Don't make everyone child of the root, obey the hierarchy
00373     QModelIndex parentIndex = indexForNode( parent );
00374 
00375 
00377     QString name = entry[ FileName ].toString().split( '/', QString::SkipEmptyParts ).last();
00378     ArchiveNode *node = parent->find( name );
00379     if ( node )
00380     {
00381         node->setEntry( entry );
00382     }
00383     else
00384     {
00385         beginInsertRows( parentIndex, m_rootNode->entries().count(), m_rootNode->entries().count() );
00386 
00387         if ( entry[ FileName ].toString().endsWith( '/' ) || ( entry.contains( IsDirectory ) && entry[ IsDirectory ].toBool() ) )
00388         {
00389             node = new ArchiveDirNode( parent, entry );
00390         }
00391         else
00392         {
00393             node = new ArchiveNode( parent, entry );
00394         }
00395         parent->entries().append( node );
00396 
00397         endInsertRows();
00398     }
00399 }
00400 
00401 void ArchiveModel::setArchive( Kerfuffle::Archive *archive )
00402 {
00403     delete m_archive;
00404     m_archive = archive;
00405     m_rootNode->clear();
00406     if ( m_archive )
00407     {
00408         Kerfuffle::ListJob *job = m_archive->list(); // TODO: call "open" or "create"?
00409 
00410         connect( job, SIGNAL( newEntry( const ArchiveEntry& ) ),
00411              this, SLOT( slotNewEntry( const ArchiveEntry& ) ) );
00412 
00413         connect( job, SIGNAL( result( KJob * ) ),
00414                  this, SIGNAL( loadingFinished() ) );
00415 
00416         if ( m_jobTracker )
00417         {
00418             m_jobTracker->registerJob( job );
00419         }
00420 
00421         emit loadingStarted();
00422         job->start();
00423     }
00424     reset();
00425 }
00426 
00427 ExtractJob* ArchiveModel::extractFile( const QVariant& fileName, const QString & destinationDir, bool preservePaths )
00428 {
00429     QList<QVariant> files;
00430     files << fileName;
00431     return extractFiles( files, destinationDir, preservePaths );
00432 }
00433 
00434 ExtractJob* ArchiveModel::extractFiles( const QList<QVariant>& files, const QString & destinationDir, bool preservePaths )
00435 {
00436     Q_ASSERT( m_archive );
00437     return m_archive->copyFiles( files, destinationDir, preservePaths );
00438 }
00439 
00440 AddJob* ArchiveModel::addFiles( const QStringList & paths )
00441 {
00442     Q_ASSERT( m_archive );
00443 
00444     if ( !m_archive->isReadOnly())
00445     {
00446         AddJob *job = m_archive->addFiles( paths );
00447         m_jobTracker->registerJob( job );
00448         connect( job, SIGNAL( newEntry( const ArchiveEntry& ) ),
00449             this, SLOT( slotNewEntry( const ArchiveEntry& ) ) );
00450         return job;
00451     }
00452     return 0;
00453 }
00454 
00455 DeleteJob* ArchiveModel::deleteFiles( const QList<QVariant> & files )
00456 {
00457     Q_ASSERT( m_archive );
00458     if ( !m_archive->isReadOnly() )
00459     {
00460         DeleteJob *job = m_archive->deleteFiles( files );
00461         m_jobTracker->registerJob( job );
00462         connect( job, SIGNAL( entryRemoved( const QString & ) ),
00463                  this, SLOT( slotEntryRemoved( const QString & ) ) );
00464         return job;
00465     }
00466     return 0;
00467 }

ark

Skip menu "ark"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

kdeutils

Skip menu "kdeutils"
  • ark
  • kcalc
  • kcharselect
  • kdelirc
  • kdessh
  • kdf
  • kfloppy
  • kgpg
  • kjots
  • klaptopdaemon
  • kmilo
  • ksim
  • ktimer
  • kwallet
  • superkaramba
Generated for kdeutils by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal