code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : QWBFS Manager
** FileName  : DiscModel.cpp
** Date      : 2010-06-16T14:19:29
** License   : GPL2
** Home Page : https://github.com/pasnox/qwbfsmanager
** Comment   : QWBFS Manager is a cross platform WBFS manager developed using C++/Qt4.
** It's currently working fine under Windows (XP to Seven, 32 & 64Bits), Mac OS X (10.4.x to 10.6.x), Linux & unix like.
**
** 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 3 of the License, or
** (at your option) any later version.
**
** This package 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, see <http://www.gnu.org/licenses/>.
**
** In addition, as a special exception, the copyright holders give permission
** to link this program with the OpenSSL project's "OpenSSL" library (or with
** modified versions of it that use the same license as the "OpenSSL"
** library), and distribute the linked executables. You must obey the GNU
** General Public License in all respects for all of the code used other than
** "OpenSSL".  If you modify file(s), you may extend this exception to your
** version of the file(s), but you are not obligated to do so. If you do not
** wish to do so, delete this exception statement from your version.
**
****************************************************************************/
#include "DiscModel.h"
#include "qwbfsdriver/Driver.h"
#include "ListView.h"

#include <FreshCore/pCoreUtils>

#include <QMimeData>
#include <QUrl>
#include <QFileInfo>
#include <QPixmapCache>
#include <QDebug>

#define URLS_FORMAT "text/uri-list"
#define WBFS_DISCS_FORMAT "xml/wbfs-disc-list"

using namespace QWBFS::Model;

// Sorter

bool SelectionRangePairLessThanSorter::operator()( const DiscModel::PairIntInt& left, const DiscModel::PairIntInt& right ) const
{
    return left.first < right.first;
}

bool SelectionRangePairGreaterThanSorter::operator()( const DiscModel::PairIntInt& left, const DiscModel::PairIntInt& right ) const
{
    return left.first > right.first;
}

HashLessThanSorter::HashLessThanSorter( int column )
{
    c = column;
}

bool HashLessThanSorter::operator()( const QWBFS::Model::Disc& left, const QWBFS::Model::Disc& right ) const
{
    int compare = 0;

    switch ( c ) {
        case 0:
            compare = 0;
            break;
        case 1:
            compare = QString::compare( left.id, right.id, Qt::CaseInsensitive );
            break;
        case 2:
            compare = QString::compare( left.title, right.title, Qt::CaseInsensitive );
            break;
        case 3:
            compare = left.size == right.size ? 0 : ( left.size < right.size ? -1 : 1 );
            break;
        case 4:
            compare = QString::compare( QWBFS::Driver::regionToString( left.region ), QWBFS::Driver::regionToString( right.region ), Qt::CaseInsensitive );
            break;
        case 5:
            compare = QString::compare( left.origin, right.origin, Qt::CaseInsensitive );
            break;
    }

    return compare == 0 ? false : compare < 0;
}

HashGreaterThanSorter::HashGreaterThanSorter( int column )
{
    c = column;
}

bool HashGreaterThanSorter::operator()( const QWBFS::Model::Disc& left, const QWBFS::Model::Disc& right ) const
{
    int compare = 0;

    switch ( c ) {
        case 0:
            compare = 0;
            break;
        case 1:
            compare = QString::compare( left.id, right.id, Qt::CaseInsensitive );
            break;
        case 2:
            compare = QString::compare( left.title, right.title, Qt::CaseInsensitive );
            break;
        case 3:
            compare = left.size == right.size ? 0 : ( left.size < right.size ? -1 : 1 );
            break;
        case 4:
            compare = QString::compare( QWBFS::Driver::regionToString( left.region ), QWBFS::Driver::regionToString( right.region ), Qt::CaseInsensitive );
            break;
        case 5:
            compare = QString::compare( left.origin, right.origin, Qt::CaseInsensitive );
            break;
    }

    return compare == 0 ? false : compare > 0;
}

// DiscModel

QStringList DiscModel::mMimeTypes = QStringList() << URLS_FORMAT << WBFS_DISCS_FORMAT;

DiscModel::DiscModel( ListView* parent, QWBFS::Driver* driver )
    : QAbstractItemModel( parent )
{
    Q_ASSERT( parent );
    mListView = parent;
    mDriver = driver;
}

DiscModel::~DiscModel()
{
}

int DiscModel::columnCount( const QModelIndex& parent ) const
{
    return parent.isValid() ? 0 : DISC_MODEL_COLUMN_COUNT;
}

QVariant DiscModel::data( const QModelIndex& index, int role ) const
{
    switch ( role ) {
        case DiscModel::ListModeSizeHintRole:
            return QSize( -1, 37 );
        case DiscModel::IconModeSizeHintRole:
            return QSize( 120, 120 );
        case DiscModel::CoverFlowModeSizeHintRole:
            return QSize( 180, 240 );
    }

    if ( !index.isValid() || index.row() < 0 || index.row() >= mDiscs.count() || index.column() < 0 || index.column() >= DISC_MODEL_COLUMN_COUNT ) {
        return QVariant();
    }

    const QWBFS::Model::Disc disc = mDiscs.value( index.row() );

    switch ( role ) {
        case Qt::DecorationRole: {
            if ( index.column() == 0 ) {
                return coverPixmap( disc.id, data( index, DiscModel::CoverFlowModeSizeHintRole ).toSize() );
            }

            break;
        }
        case Qt::DisplayRole: {
            switch ( index.column() ) {
                case 0:
                    return QVariant();
                case 1:
                    return disc.id;
                case 2:
                    return pCoreUtils::toTitleCase( disc.title );
                case 3:
                    return pCoreUtils::fileSizeToString( disc.size );
                case 4:
                    return QWBFS::Driver::regionToString( disc.region );
                case 5:
                    return disc.origin;
            }

            break;
        }
        case Qt::ToolTipRole: {
            QStringList values;

            if ( !disc.id.isEmpty() ) {
                values << tr( "Id: %1" ).arg( disc.id );
            }

            values << tr( "Title: %1" ).arg( pCoreUtils::toTitleCase( disc.title ) );
            values << tr( "Size: %1" ).arg( pCoreUtils::fileSizeToString( disc.size ) );
            values << tr( "Origin: %1" ).arg( disc.origin );
            values << tr( "Region: %1" ).arg( QWBFS::Driver::regionToString( disc.region ) );
            values << tr( "State: %1" ).arg( QWBFS::Driver::stateToString( QWBFS::Driver::State( disc.state ) ) );
            values << tr( "Error: %1" ).arg( QWBFS::Driver::errorToString( QWBFS::Driver::Error( disc.error ) ) );

            return values.join( "\n" );
        }
    }

    return QVariant();
}

QModelIndex DiscModel::index( int row, int column, const QModelIndex& parent ) const
{
    if ( parent.isValid() || row < 0 || row >= mDiscs.count() || column < 0 || column >= DISC_MODEL_COLUMN_COUNT ) {
        return QModelIndex();
    }

    return createIndex( row, column, row );
}

QModelIndex DiscModel::parent( const QModelIndex& index ) const
{
    Q_UNUSED( index );
    return QModelIndex();
}

int DiscModel::rowCount( const QModelIndex& parent ) const
{
    return parent.isValid() ? 0 : mDiscs.count();
}

bool DiscModel::hasChildren( const QModelIndex& parent ) const
{
    return parent.isValid() ? false : !mDiscs.isEmpty();
}

Qt::ItemFlags DiscModel::flags( const QModelIndex& index ) const
{
    Qt::ItemFlags f = QAbstractItemModel::flags( index );

    if ( index.isValid() ) {
        f |= Qt::ItemIsDragEnabled;
    }
    else {
        f |= Qt::ItemIsDropEnabled;
    }

    return f;
}

bool DiscModel::removeRows( int row, int count, const QModelIndex& parent )
{
    count = qBound( count, count, mDiscs.count() -row ); // -1

    if ( parent.isValid() || row >= mDiscs.count() || count <= 0 ) {
        return false;
    }

    beginRemoveRows( QModelIndex(), row, row +count -1 );
    for ( int i = 0; i < count; i++ ) {
        mIndexes.remove( mDiscs.at( i ).id );
        mDiscs.removeAt( row );
    }
    endRemoveRows();

    emit countChanged( mDiscs.count() );

    return true;
}

bool DiscModel::setData( const QModelIndex& index, const QVariant& value, int role )
{
    if ( !index.isValid() || index.row() < 0 || index.row() >= mDiscs.count() || index.column() < 0 || index.column() >= DISC_MODEL_COLUMN_COUNT ) {
        return false;
    }

    switch ( role )
    {
        case Qt::DecorationRole: {
            switch ( index.column() ) {
                case 0:
                    break;
                default:
                    return false;
            }

            break;
        }
        case Qt::DisplayRole: {
            switch ( index.column() ) {
                case 0:
                    return false;
                case 1:
                    mDiscs[ index.row() ].id = value.toString();
                    break;
                case 2:
                    mDiscs[ index.row() ].title = value.toString();
                    break;
                case 3:
                    mDiscs[ index.row() ].size = value.toUInt();
                    break;
                case 4:
                    mDiscs[ index.row() ].region = value.toInt();
                    break;
                case 5:
                    mDiscs[ index.row() ].origin = value.toString();
                    break;
            }

            break;
        }
        default:
            return false;
    }

    emit dataChanged( index.sibling( index.row(), 0 ), index.sibling( index.row(), DISC_MODEL_COLUMN_COUNT -1 ) );
    return true;
}

QVariant DiscModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
    if ( orientation == Qt::Horizontal && section >= 0 && section < DISC_MODEL_COLUMN_COUNT ) {
        switch ( role ) {
            case Qt::DisplayRole: {
                switch ( section ) {
                    case 0:
                        return tr( "Image" );
                    case 1:
                        return tr( "Id" );
                    case 2:
                        return tr( "Title" );
                    case 3:
                        return tr( "Size" );
                    case 4:
                        return tr( "Region" );
                    case 5:
                        return tr( "Origin" );
                }

                break;
            }
            case Qt::ToolTipRole: {
                switch ( section ) {
                    case 0:
                        break; // nothing to sort
                    case 1:
                        return tr( "Sort by Id" );
                    case 2:
                        return tr( "Sort by Title" );
                    case 3:
                        return tr( "Sort by Size" );
                    case 4:
                        return tr( "Sort by Region" );
                    case 5:
                        break; // nothing to sort
                }

                break;
            }
        }
    }

    return QAbstractItemModel::headerData( section, orientation, role );
}

void DiscModel::sort( int column, Qt::SortOrder order )
{
    /*
    Call beginLayoutChanged()
    Remember the QModelIndex that will change
    Update your internal data
    Call changePersistentIndex()
    Call endLayoutChanged()
    */

    emit layoutAboutToBeChanged();

    QModelIndexList oldIndexes = persistentIndexList();
    QWBFS::Model::DiscList newDiscs = mDiscs;
    QModelIndexList newIndexes;
    QHash<int, int> mapping; // old row, new row

    for ( int i = 0; i < mDiscs.count(); i++ ) {
        mapping[ i ] = i;
    }

    if ( order == Qt::AscendingOrder ) {
        HashLessThanSorter lesser( column );
        qSort( newDiscs.begin(), newDiscs.end(), lesser );
    }
    else {
        HashGreaterThanSorter greater( column );
        qSort( newDiscs.begin(), newDiscs.end(), greater );
    }

    for ( int i = 0; i < newDiscs.count(); i++ ) {
        mapping[ index( newDiscs[ i ] ).row() ] = i;
    }

    foreach ( const QModelIndex& index, oldIndexes ) {
        newIndexes << createIndex( mapping[ index.row() ], index.column(), mapping[ index.row() ] );
    }

    mDiscs = newDiscs;
    changePersistentIndexList( oldIndexes, newIndexes );

    emit layoutChanged();
}

Qt::DropActions DiscModel::supportedDropActions() const
{
    return Qt::CopyAction;
}

bool DiscModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
{
    Q_UNUSED( action );
    Q_UNUSED( row );
    Q_UNUSED( column );
    Q_UNUSED( parent );

    QSet<QWBFS::Model::Disc> discs;

    if ( data->formats().contains( WBFS_DISCS_FORMAT ) ) {
        discs = QWBFS::Model::Disc::fromByteArray( data->data( WBFS_DISCS_FORMAT ) ).toSet();
    }
    else if ( data->formats().contains( URLS_FORMAT ) ) {
        foreach ( const QUrl& url, data->urls() ) {
            const QFileInfo file( url.toLocalFile() );

            if ( !file.isDir() && file.exists() ) {
                const QString fileName = QFileInfo( file.isSymLink() ? file.symLinkTarget() : file.absoluteFilePath() ).canonicalFilePath();
                QWBFS::Model::Disc disc;
                const int result = mDriver->discImageInfo( fileName, disc );

                if ( result != Driver::Ok ) {
                    continue;
                }

                discs << disc;
            }
        }
    }

    // remove clones
    foreach ( const QWBFS::Model::Disc& disc, mDiscs ) {
        if ( discs.contains( disc ) ) {
            discs.remove( disc );
        }
    }

    // remove drop from same view
    if ( mDriver ) {
        foreach ( const QWBFS::Model::Disc& disc, discs ) {
            if ( disc.origin == mDriver->partition() ) {
                discs.remove( disc );
            }
        }
    }

    if ( discs.isEmpty() ) {
        return false;
    }

    addDiscs( discs.toList() );
    return true;
}

QMimeData* DiscModel::mimeData( const QModelIndexList& indexes ) const
{
    if ( indexes.isEmpty() || !mDriver || ( mDriver && !mDriver->isOpen() ) ) {
        return 0;
    }

    QWBFS::Model::DiscList discs;

    foreach ( const QModelIndex& index, indexes ) {
        discs << disc( index );
    }

    QMimeData* data = new QMimeData;
    data->setData( WBFS_DISCS_FORMAT, QWBFS::Model::Disc::toByteArray( discs ) );

    return data;
}

QStringList DiscModel::mimeTypes() const
{
    return mMimeTypes;
}

QPixmap DiscModel::coverPixmap( const QString& id, const QSize& size, bool coverFlow ) const
{
    if ( view()->viewIconType() == QWBFS::WiiTDB::Cover || coverFlow ) {
        return QWBFS::WiiTDB::coverBoxPixmap( id, view()->cacheManager(), size );
    }

    return QWBFS::WiiTDB::coverDiscPixmap( id, view()->cacheManager(), size );
}

QPixmap DiscModel::statePixmap( int state, const QSize& size ) const
{
    const QString url = state == QWBFS::Driver::Success ? ":/icons/256/success.png" : ":/icons/256/error.png";
    const QString key = QString( "%1-%2-%3" ).arg( url ).arg( size.width() ).arg( size.height() );
    QPixmap pixmap;

    if ( !QPixmapCache::find( key, pixmap ) ) {
        if ( pixmap.load( url ) ) {
            pixmap = pixmap.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
            QPixmapCache::insert( key, pixmap );
        }
    }

    return pixmap;
}

ListView* DiscModel::view() const
{
    return mListView;
}

void DiscModel::insertDiscs( int index, const QWBFS::Model::DiscList& discs )
{
    index = qBound( 0, index, rowCount() );

    if ( discs.isEmpty() ) {
        return;
    }

    beginInsertRows( QModelIndex(), index, discs.count() -1 );
    for ( int i = 0; i < discs.count(); i++ ) {
        const QWBFS::Model::Disc& disc = discs.at( i );
        mDiscs.insert( i +index, discs.at( i ) );
        mIndexes[ disc.id ] = this->index( disc );
    }
    endInsertRows();

    emit countChanged( mDiscs.count() );
}

void DiscModel::addDiscs( const QWBFS::Model::DiscList& discs )
{
    insertDiscs( rowCount(), discs );
}

void DiscModel::setDiscs( const QWBFS::Model::DiscList& discs )
{
    clear();
    addDiscs( discs );
}

void DiscModel::setDisc( const QModelIndex& index, const QWBFS::Model::Disc& disc )
{
    if ( !index.isValid() || index.row() < 0 || index.row() >= mDiscs.count() || index.column() < 0 || index.column() >= DISC_MODEL_COLUMN_COUNT ) {
        return;
    }

    mDiscs[ index.row() ] = disc;
    mIndexes[ disc.id ] = this->index( disc );
    emit dataChanged( index.sibling( index.row(), 0 ), index.sibling( index.row(), DISC_MODEL_COLUMN_COUNT -1 ) );
}

QWBFS::Model::DiscList DiscModel::discs() const
{
    return mDiscs;
}

QWBFS::Model::DiscList DiscModel::discs( const QModelIndexList& indexes )
{
    QWBFS::Model::DiscList discs;
    QSet<int> rows;

    foreach ( const QModelIndex& index, indexes ) {
        if ( !rows.contains( index.row() ) ) {
            rows << index.row();
            discs << disc( index );
        }
    }

    return discs;
}

QWBFS::Model::DiscList DiscModel::discs( const QItemSelection& selection )
{
    return discs( selection.indexes() );
}

QWBFS::Model::Disc DiscModel::disc( const QModelIndex& index ) const
{
    return mDiscs.value( index.row() );
}

QModelIndex DiscModel::index( const QString& id ) const
{
    return mIndexes.value( id );
}

QModelIndex DiscModel::index( const QWBFS::Model::Disc& disc, int column ) const
{
    const int index = mDiscs.indexOf( disc );
    return index == -1 ? QModelIndex() : createIndex( index, column, index );
}

QString DiscModel::discId( const QModelIndex& index ) const
{
    return disc( index ).id;
}

void DiscModel::removeSelection( const QItemSelection& _selection )
{
    QList<DiscModel::PairIntInt> selection;

    // get pair selection
    foreach ( const QItemSelectionRange& range, _selection ) {
        selection << qMakePair( range.top(), range.height() );
    }

    // reverse order to remove last items first
    SelectionRangePairGreaterThanSorter sorter;
    qSort( selection.begin(), selection.end(), sorter );

    // remove items
    foreach ( const DiscModel::PairIntInt& pair, selection ) {
        removeRows( pair.first, pair.second, QModelIndex() );
    }
}

void DiscModel::updateDisc( const QWBFS::Model::Disc& disc )
{
    const int row = mDiscs.indexOf( disc );

    if ( row != -1 ) {
        const QModelIndex index = this->index( disc );
        mDiscs[ row ] = disc;
        emit dataChanged( index.sibling( index.row(), 0 ), index.sibling( index.row(), DISC_MODEL_COLUMN_COUNT -1 ) );
    }
}

qint64 DiscModel::size() const
{
    qint64 size = 0;

    foreach ( const QWBFS::Model::Disc& disc, mDiscs ) {
        size += disc.size;
    }

    return size;
}

void DiscModel::clear()
{
    if ( mDiscs.isEmpty() ) {
        return;
    }

    beginRemoveRows( QModelIndex(), 0, mDiscs.count() -1 );
    mDiscs.clear();
    mIndexes.clear();
    endRemoveRows();

    emit countChanged( mDiscs.count() );
}


code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : QWBFS Manager
** FileName  : DiscModel.h
** Date      : 2010-06-16T14:19:29
** License   : GPL2
** Home Page : https://github.com/pasnox/qwbfsmanager
** Comment   : QWBFS Manager is a cross platform WBFS manager developed using C++/Qt4.
** It's currently working fine under Windows (XP to Seven, 32 & 64Bits), Mac OS X (10.4.x to 10.6.x), Linux & unix like.
**
** 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 3 of the License, or
** (at your option) any later version.
**
** This package 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, see <http://www.gnu.org/licenses/>.
**
** In addition, as a special exception, the copyright holders give permission
** to link this program with the OpenSSL project's "OpenSSL" library (or with
** modified versions of it that use the same license as the "OpenSSL"
** library), and distribute the linked executables. You must obey the GNU
** General Public License in all respects for all of the code used other than
** "OpenSSL".  If you modify file(s), you may extend this exception to your
** version of the file(s), but you are not obligated to do so. If you do not
** wish to do so, delete this exception statement from your version.
**
****************************************************************************/
#ifndef DISCMODEL_H
#define DISCMODEL_H

#include <QAbstractItemModel>
#include <QStringList>
#include <QItemSelection>

#include "Disc.h"

class ListView;

namespace QWBFS {
class Driver;
namespace Model {

#define DISC_MODEL_COLUMN_COUNT 6

class DiscModel : public QAbstractItemModel
{
    Q_OBJECT

public:
    typedef QPair<int, int> PairIntInt;

    enum CustomRole {
        ListModeSizeHintRole = Qt::UserRole,
        IconModeSizeHintRole,
        CoverFlowModeSizeHintRole
    };

    DiscModel( ListView* parent = 0, QWBFS::Driver* driver = 0 );
    virtual ~DiscModel();

    virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const;
    virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
    virtual QModelIndex index( int row, int column, const QModelIndex& parent = QModelIndex() ) const;
    virtual QModelIndex parent( const QModelIndex& index ) const;
    virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;

    virtual bool hasChildren( const QModelIndex& parent = QModelIndex() ) const;
    virtual Qt::ItemFlags flags( const QModelIndex& index ) const;
    virtual bool removeRows( int row, int count, const QModelIndex& parent = QModelIndex() );
    virtual bool setData( const QModelIndex& index, const QVariant& value, int role = Qt::EditRole );
    virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
    virtual void sort( int column, Qt::SortOrder order = Qt::AscendingOrder );

    virtual Qt::DropActions supportedDropActions() const;
    virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent );
    virtual QMimeData* mimeData( const QModelIndexList& indexes ) const;
    virtual QStringList mimeTypes() const;

    QPixmap coverPixmap( const QString& id, const QSize& size, bool coverFlow = false ) const;
    QPixmap statePixmap( int state, const QSize& size ) const;

    ListView* view() const;

    void insertDiscs( int index, const QWBFS::Model::DiscList& discs );
    void addDiscs( const QWBFS::Model::DiscList& discs );
    void setDiscs( const QWBFS::Model::DiscList& discs );
    void setDisc( const QModelIndex& index, const QWBFS::Model::Disc& disc );
    QWBFS::Model::DiscList discs() const;
    QWBFS::Model::DiscList discs( const QModelIndexList& indexes );
    QWBFS::Model::DiscList discs( const QItemSelection& selection );
    QWBFS::Model::Disc disc( const QModelIndex& index ) const;
    QModelIndex index( const QString& id ) const;
    QModelIndex index( const QWBFS::Model::Disc& disc, int column = 0 ) const;
    QString discId( const QModelIndex& index ) const;
    void removeSelection( const QItemSelection& selection );
    void updateDisc( const QWBFS::Model::Disc& disc );
    qint64 size() const;

public slots:
    void clear();

protected:
    ListView* mListView;
    Driver* mDriver;
    QWBFS::Model::DiscList mDiscs;
    QHash<QString, QPersistentModelIndex> mIndexes;

    static QStringList mMimeTypes;

signals:
    void countChanged( int count );
};

struct SelectionRangePairLessThanSorter
{
    bool operator()( const DiscModel::PairIntInt& left, const DiscModel::PairIntInt& right ) const;
};

struct SelectionRangePairGreaterThanSorter
{
    bool operator()( const DiscModel::PairIntInt& left, const DiscModel::PairIntInt& right ) const;
};

struct HashLessThanSorter
{
    HashLessThanSorter( int column );

    bool operator()( const QWBFS::Model::Disc& left, const QWBFS::Model::Disc& right ) const;

    int c;
};

struct HashGreaterThanSorter
{
    HashGreaterThanSorter( int column );

    bool operator()( const QWBFS::Model::Disc& left, const QWBFS::Model::Disc& right ) const;

    int c;
};

}; // Models
}; // QWBFS

#endif // DISCMODEL_H

repo_name: CYBERDEViL/qwbfsmanager

license: unknown


code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : Fresh Library
** FileName  : PartitionDelegate.cpp
** Date      : 2011-02-20T00:41:09
** License   : LGPL v3
** Home Page : http://bettercodes.org/projects/fresh
** Comment   : Fresh Library is a Qt 4 extension library providing set of new core & gui classes.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Leser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This package 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : QWBFS Manager
** FileName  : PartitionDelegate.cpp
** Date      : 2010-06-16T14:19:29
** License   : GPL2
** Home Page : https://github.com/pasnox/qwbfsmanager
** Comment   : QWBFS Manager is a cross platform WBFS manager developed using C++/Qt4.
** It's currently working fine under Windows (XP to Seven, 32 & 64Bits), Mac OS X (10.4.x to 10.6.x), Linux & unix like.
**
** 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 3 of the License, or
** (at your option) any later version.
**
** This package 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, see <http://www.gnu.org/licenses/>.
**
** In addition, as a special exception, the copyright holders give permission
** to link this program with the OpenSSL project's "OpenSSL" library (or with
** modified versions of it that use the same license as the "OpenSSL"
** library), and distribute the linked executables. You must obey the GNU
** General Public License in all respects for all of the code used other than
** "OpenSSL".  If you modify file(s), you may extend this exception to your
** version of the file(s), but you are not obligated to do so. If you do not
** wish to do so, delete this exception statement from your version.
**
****************************************************************************/
#include "PartitionDelegate.h"
#include "Utils.h"
#include "models/pPartitionModel.h"
#include "qwbfsdriver/Driver.h"

#include <FreshCore/pCoreUtils>

#include <QPainter>
#include <QStyleFactory>
#include <QFileInfo>
#include <QDebug>

#define COMBOBOX_ITEM_HEIGHT 30

PartitionDelegate::PartitionDelegate( pPartitionModel* parent )
    : QStyledItemDelegate( parent )
{
    Q_ASSERT( parent );
    mModel = parent;
    mStyle = Utils::neutralStyle();
}

PartitionDelegate::~PartitionDelegate()
{
}

void PartitionDelegate::paint( QPainter* painter, const QStyleOptionViewItem& _option, const QModelIndex& index ) const
{
    QStyleOptionViewItemV4 option = _option;
    initStyleOption( &option, index );
    option.palette = mStyle->standardPalette();
#if defined( Q_OS_MAC )
    option.font.setPointSize( option.font.pointSize() -2 );
#endif

    const bool selected = option.state & QStyle::State_Selected;
    const bool hovered = option.state & QStyle::State_MouseOver;
    const int margin = option.widget->inherits( "QAbstractItemView" ) ? 3 : 0;
    const qint64 wbfsFSId = 0x25;
    pPartition partition = mModel->partition( index );

    if ( partition.property( pPartition::FileSystemId ).toLongLong() == wbfsFSId ) {
        // update wbfs partitions informations
        if ( partition.property( pPartition::LastCheck ).toDateTime() < QDateTime::currentDateTime()
            && ( partition.property( pPartition::UsedSize ).toLongLong() == -1 || partition.property( pPartition::FreeSize ).toLongLong() == -1 ) ) {
            // use a scope to avoid problems with windows partition read locked
            {
                bool created = false;
                QWBFS::Partition::Handle handle = QWBFS::Driver::getHandle( partition.property( pPartition::DevicePath ).toString(), &created );
                QWBFS::Driver driver( handle );
                QWBFS::Partition::Status status;

                driver.status( status );
                partition.updateSizes( status.size, status.free );

                if ( created ) {
                    QWBFS::Driver::closeHandle( handle );
                }
            }

            mModel->updatePartition( partition );
        }
    }

    int total = 100;
    int used = ( (qreal)partition.property( pPartition::UsedSize ).toLongLong() /(qreal)partition.property( pPartition::TotalSize ).toLongLong() ) *(qreal)100;

    QStyleOptionProgressBarV2 pbOption;
    pbOption.initFrom( option.widget );
    pbOption.state = option.state;
    pbOption.palette = option.palette;
    pbOption.rect = option.rect.adjusted( margin, margin, -margin, -margin );
    pbOption.bottomToTop = false;
    pbOption.invertedAppearance = false;
    pbOption.orientation = Qt::Horizontal;
    pbOption.maximum = total;
    pbOption.minimum = 0;
    pbOption.progress = used;
    pbOption.text = QString::null;
    pbOption.textAlignment = Qt::AlignCenter;
    pbOption.textVisible = false;

    pbOption.palette.setColor( QPalette::Highlight, QColor( 0, 160, 0, 100 ) );

    QStyleOptionButton bOption;
    bOption.initFrom( option.widget );
    bOption.state = option.state;
    bOption.palette = option.palette;
    bOption.rect = option.rect.adjusted( margin, margin, -margin, -margin );
    //bOption.icon = partition.fileSystem == "WBFS" ? QIcon( ":/icons/256/wii.png" ) : partition.icon();
    bOption.iconSize = QSize( bOption.rect.height() -5, bOption.rect.height() -5 );
    bOption.text = QString( "%1 - %2" )
        .arg( partition.property( pPartition::DisplayText ).toString() )
        .arg( pCoreUtils::fileSizeToString( partition.property( pPartition::TotalSize ).toLongLong() ) )
        ;

    if ( selected || hovered ) {
        paintFrame( painter, &option, selected );
    }

    painter->setFont( option.font );

    mStyle->drawControl( QStyle::CE_ProgressBar, &pbOption, painter, option.widget );
    mStyle->drawControl( QStyle::CE_PushButtonLabel, &bOption, painter, option.widget );
}

QSize PartitionDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
    Q_UNUSED( option );
    Q_UNUSED( index );
    return QSize( -1, COMBOBOX_ITEM_HEIGHT );
}

void PartitionDelegate::paintFrame( QPainter* painter, const QStyleOption* option, bool pair ) const
{
    const int corner = 5;
    const QRect r = option->rect.adjusted( 0, 0, -1, -1 );
    const QPalette::ColorRole role = pair ? QPalette::Highlight : QPalette::Button;
    QColor strokeColor = option->palette.color( role ).darker();
    QColor fillColor1 = option->palette.color( role ).lighter();
    QColor fillColor2 = option->palette.color( role );

    if ( option->state & QStyle::State_MouseOver ) {
        const int factor = 110;
        strokeColor = strokeColor.darker( factor );
        fillColor1 = fillColor1.darker( factor );
        fillColor2 = fillColor2.darker( factor );
    }

    QLinearGradient gradient( option->rect.topLeft(), option->rect.bottomLeft() );
    gradient.setColorAt( 0, fillColor1 );
    gradient.setColorAt( 1, fillColor2 );

    painter->setPen( strokeColor );
    painter->setBrush( gradient );
    painter->drawRoundedRect( r, corner, corner );
}


code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : Fresh Library
** FileName  : PartitionDelegate.h
** Date      : 2011-02-20T00:41:09
** License   : LGPL v3
** Home Page : http://bettercodes.org/projects/fresh
** Comment   : Fresh Library is a Qt 4 extension library providing set of new core & gui classes.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Leser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This package 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : QWBFS Manager
** FileName  : PartitionDelegate.h
** Date      : 2010-06-16T14:19:29
** License   : GPL2
** Home Page : https://github.com/pasnox/qwbfsmanager
** Comment   : QWBFS Manager is a cross platform WBFS manager developed using C++/Qt4.
** It's currently working fine under Windows (XP to Seven, 32 & 64Bits), Mac OS X (10.4.x to 10.6.x), Linux & unix like.
**
** 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 3 of the License, or
** (at your option) any later version.
**
** This package 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, see <http://www.gnu.org/licenses/>.
**
** In addition, as a special exception, the copyright holders give permission
** to link this program with the OpenSSL project's "OpenSSL" library (or with
** modified versions of it that use the same license as the "OpenSSL"
** library), and distribute the linked executables. You must obey the GNU
** General Public License in all respects for all of the code used other than
** "OpenSSL".  If you modify file(s), you may extend this exception to your
** version of the file(s), but you are not obligated to do so. If you do not
** wish to do so, delete this exception statement from your version.
**
****************************************************************************/
#ifndef PARTITIONDELEGATE_H
#define PARTITIONDELEGATE_H

/*!
    \file PartitionDelegate.h
    \brief A delegate for drawing the representation of a pPartition.
    \author Filipe Azevedo aka Nox P\@sNox <pasnox@gmail.com>
*/

#include <QStyledItemDelegate>

class pPartitionModel;

/*!
    \ingroup Gui
    \class PartitionDelegate
    \brief A delegate for drawing the representation of a pPartition.
*/
class PartitionDelegate : public QStyledItemDelegate
{
    Q_OBJECT

public:
    /*!
        Create a instance of the delegate having \a parent as parent and model.
    */
    PartitionDelegate( pPartitionModel* parent );
    /*!
        Destroys the instance of the delegate.
    */
    virtual ~PartitionDelegate();
    /*!
        Reimplemented.
    */
    virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
    /*!
        Reimplemented.
    */
    virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;

protected:
    pPartitionModel* mModel;
    QStyle* mStyle;

    void paintFrame( QPainter* painter, const QStyleOption* option, bool pair = true ) const;
};

#endif // PARTITIONDELEGATE_H


code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : Fresh Library
** FileName  : pPartition.cpp
** Date      : 2011-02-20T00:41:35
** License   : LGPL v3
** Home Page : http://bettercodes.org/projects/fresh
** Comment   : Fresh Library is a Qt 4 extension library providing set of new core & gui classes.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Leser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This package 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "pPartition.h"

#include <QStringList>
#include <QFileInfo>
#include <QFile>
#include <QDebug>

#if defined( Q_OS_WIN )
#include <FreshCore/pWinHelpers>
#include <qt_windows.h>
#include <winioctl.h>
#endif

#define PROPERTY_DISPLAY_TEXT "_DISPLAY_TEXT"
#define PROPERTY_LAST_CHECK "_LAST_CHECK"

pPartition::pPartition( const QString& devicePath, bool checkValidity )
{
    if ( !checkValidity || ( checkValidity && isValidDevicePath( devicePath ) ) ) {
        mDevicePath = devicePath;
    }
}

bool pPartition::operator==( const pPartition& other ) const
{
    return devicePath() == other.devicePath();
}

void pPartition::setProperties( const QVariantMap& properties )
{
    mProperties = properties;
    mDevicePath.clear();
    mProperties[ PROPERTY_DISPLAY_TEXT ] = generateDisplayText();
    updateLastChecked();
}

QVariantMap pPartition::properties() const
{
    return mProperties;
}

QVariant pPartition::property( pPartition::Property property ) const
{
#if defined( Q_OS_MAC )
    switch ( property ) {
        case Label:
            return mProperties.value( "DAVolumeName", value( "DAMediaName" ) ).toString().simplified();
        case DevicePath:
            return ( mDevicePath.isEmpty() ? QString( "/dev/%1" ).arg( value( "DAMediaBSDName" ) ) : mDevicePath ).simplified();
        case TotalSize:
            return mProperties.value( "DAMediaSize", -1 );
        case UsedSize:
            return mProperties.value( "DAMediaUsed", -1 );
        case FreeSize:
            return mProperties.value( "DAMediaFree", -1 );
        /*case DeviceType:
            return mProperties.value( PROPERTY_DEVICE_TYPE );*/
        case MountPoints:
            return mProperties.value( "DAVolumePath" );
        case FileSystem:
            return mProperties.value( "DAVolumeKind", value( "DAMediaContent" ) ).toString().toUpper().replace( "_", " " ).simplified();
        case FileSystemId:
            return mProperties.value( "DAVolumeKindId" ).toString().toLongLong();
        case DeviceVendor:
            return mProperties.value( "DADeviceVendor" ).toString().replace( "_", " " ).simplified();
        case DeviceModel:
            return mProperties.value( "DADeviceModel" ).toString().replace( "_", " " ).simplified();
        case DisplayText:
            return mProperties.value( PROPERTY_DISPLAY_TEXT ).toString().simplified();
        case LastCheck:
            return mProperties.value( PROPERTY_LAST_CHECK );
    }
#elif defined( Q_OS_LINUX )
    switch ( property ) {
        case Label:
            return mProperties.value( "ID_FS_LABEL" ).toString().simplified();
        case DevicePath:
            return ( mDevicePath.isEmpty() ? value( "DEVNAME" ) : mDevicePath ).simplified();
        case TotalSize:
            return mProperties.value( "UDISKS_PARTITION_SIZE", -1 );
        case UsedSize:
            return mProperties.value( "UDISKS_PARTITION_USED", -1 );
        case FreeSize:
            return mProperties.value( "UDISKS_PARTITION_FREE", -1 );
        /*case DeviceType:
            return mProperties.value( PROPERTY_DEVICE_TYPE );*/
        case MountPoints:
            return mProperties.value( "UDISKS_PARTITION_MOUNT_POINTS" );
        case FileSystem:
            return mProperties.value( "ID_FS_TYPE" ).toString().toUpper().replace( "_", " " ).simplified();
        case FileSystemId:
            return mProperties.value( "UDISKS_PARTITION_TYPE" ).toString().toLongLong();
        case DeviceVendor:
            return mProperties.value( "ID_VENDOR" ).toString().replace( "_", " " ).simplified();
        case DeviceModel:
            return mProperties.value( "ID_MODEL" ).toString().replace( "_", " " ).simplified();
        case DisplayText:
            return mProperties.value( PROPERTY_DISPLAY_TEXT ).toString().simplified();
        case LastCheck:
            return mProperties.value( PROPERTY_LAST_CHECK );
    }
#elif defined( Q_OS_WIN )
    switch ( property ) {
        case Label:
            return mProperties.value( "LABEL" ).toString().simplified();
        case DevicePath:
            return ( mDevicePath.isEmpty() ? value( "DEVICE" ) : mDevicePath ).simplified();
        case TotalSize:
            return mProperties.value( "SIZE", -1 );
        case UsedSize:
            return mProperties.value( "USED", -1 );
        case FreeSize:
            return mProperties.value( "FREE", -1 );
        /*case DeviceType:
            return mProperties.value( PROPERTY_DEVICE_TYPE );*/
        case MountPoints:
            return mProperties.value( "MOUNT_POINTS" );
        case FileSystem:
            return mProperties.value( "FS_TYPE" ).toString().toUpper().replace( "_", " " ).simplified();
        case FileSystemId:
            return mProperties.value( "FS_TYPE_ID" ).toString().toLongLong();
        case DeviceVendor:
            return mProperties.value( "ID_VENDOR" ).toString().replace( "_", " " ).simplified();
        case DeviceModel:
            return mProperties.value( "ID_MODEL" ).toString().replace( "_", " " ).simplified();
        case DisplayText:
            return mProperties.value( PROPERTY_DISPLAY_TEXT ).toString().simplified();
        case LastCheck:
            return mProperties.value( PROPERTY_LAST_CHECK );
    }
#endif

    return QVariant();
}

QVariant pPartition::property( const QString& property ) const
{
    return mProperties.value( property );
}

void pPartition::updateSizes( qint64 total, qint64 free )
{
#if defined( Q_OS_MAC )
    mProperties[ "DAMediaSize" ] = total;
    mProperties[ "DAMediaUsed" ] = free == -1 ? -1 : total -free;
    mProperties[ "DAMediaFree" ] = free;
#elif defined( Q_OS_LINUX )
    mProperties[ "UDISKS_PARTITION_SIZE" ] = total;
    mProperties[ "UDISKS_PARTITION_USED" ] = free == -1 ? -1 : total -free;
    mProperties[ "UDISKS_PARTITION_FREE" ] = free;
#elif defined( Q_OS_WIN )
    mProperties[ "SIZE" ] = total;
    mProperties[ "USED" ] = free == -1 ? -1 : total -free;
    mProperties[ "FREE" ] = free;
#endif
    updateLastChecked();
}

bool pPartition::isValid() const
{
    return isValidDevicePath( devicePath() );
}

bool pPartition::isCustom() const
{
    return devicePath() == mDevicePath;
}

QString pPartition::devicePath() const
{
    return property( pPartition::DevicePath ).toString();
}

void pPartition::updateLastChecked()
{
    mProperties[ PROPERTY_LAST_CHECK ] = QDateTime::currentDateTime();
}

QString pPartition::generateDisplayText() const
{
    const QString label = property( pPartition::Label ).toString().isEmpty() ? devicePath() : property( pPartition::Label ).toString();
    const QString vendorModel = QString( "%1 %2" )
        .arg( property( pPartition::DeviceVendor ).toString() )
        .arg( property( pPartition::DeviceModel ).toString() )
        .simplified()
        ;

    return QString( "%1 (%2/%3)" )
        .arg( label )
        .arg( property( pPartition::FileSystem ).toString() )
        .arg( vendorModel.isEmpty() ? QObject::tr( QT_TRANSLATE_NOOP( "pPartition", "Unknown Vendor/Model" ) ) : vendorModel )
        .simplified()
        ;
}

bool pPartition::isWBFSPartition( const QString& devicePath )
{
    QString filePath = devicePath;

#if defined( Q_OS_WIN )
    if ( !filePath.isEmpty() && filePath.length() <= 3 ) {
        filePath = QString( "\\\\?\\%1:" ).arg( filePath[ 0 ] );
        DISK_GEOMETRY diskGeometry;
        HANDLE handle = CreateFile( QStringToTCHAR( filePath ), GENERIC_READ | FILE_SHARE_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL );

        if ( handle != INVALID_HANDLE_VALUE ) {
            DWORD bytes;

            if ( DeviceIoControl( handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &diskGeometry, sizeof(DISK_GEOMETRY), &bytes, NULL ) ) {
                const DWORD sectorSize = diskGeometry.BytesPerSector;
                char buffer[ sectorSize  ];
                DWORD read;

                if ( ReadFile( handle, buffer, sectorSize, &read, NULL ) ) {
                    CloseHandle( handle );
                    return QByteArray( buffer ).left( 4 ).toLower() == "wbfs";
                }
            }
        }

        CloseHandle( handle );
        return false;
    }
#endif

    QFile file( filePath );

    if ( file.open( QIODevice::ReadOnly ) ) {
        return file.read( 4 ).toLower() == "wbfs";
    }

    return false;
}

bool pPartition::isValidDevicePath( const QString& devicePath )
{
    QString filePath = devicePath;

#if defined( Q_OS_WIN )
    if ( !filePath.isEmpty() && filePath.length() <= 3 ) {
        filePath = QString( "\\\\?\\%1:" ).arg( filePath[ 0 ] );
        HANDLE handle = CreateFile( QStringToTCHAR( filePath ), GENERIC_READ | FILE_SHARE_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL );

        if ( handle != INVALID_HANDLE_VALUE ) {
            CloseHandle( handle );
            return true;
        }

        return false;
    }
#endif

    const QFileInfo file( filePath );
    return !filePath.isEmpty() && file.exists() && !file.isDir();
}

QString pPartition::value( const QString& key ) const
{
    return mProperties.value( key ).toString();
}

QString pPartition::fileSystemIdToString( qint64 id, pPartition::Type type, bool full )
{
    typedef QPair<QString, QString> Info;
    typedef QList<Info> InfoList;
    QHash<qint64, InfoList> hash;

    if ( type == pPartition::Disc ) {
        hash[ 0x00 ] << Info( "Unformatted", "NO-Partition empty partition-table entry" );
        hash[ 0x01 ] << Info( "CD_DA", "CD_DA" );
        hash[ 0x02 ] << Info( "CD_ROM_Mode_1", "CD_ROM_Mode_1" );
        hash[ 0x03 ] << Info( "CD_ROM_Mode_2", "CD_ROM_Mode_2" );
        hash[ 0x04 ] << Info( "CD_ROM_Mode_2_Form_1", "CD_ROM_Mode_2_Form_1" );
        hash[ 0x05 ] << Info( "CD_ROM_Mode_2_Form_2", "CD_ROM_Mode_2_Form_2" );
    }
    else {
        hash[ 0x00 ] << Info( "Unformatted", "NO-Partition empty partition-table entry" );
        hash[ 0x01 ] << Info( "FAT12", "DOS DOS 12-bit FAT" );
        hash[ 0x02 ] << Info( "Xenix", "XENIX root file system" );
        hash[ 0x03 ] << Info( "Xenix", "XENIX /usr file system (obsolete)" );
        hash[ 0x04 ] << Info( "FAT16", "DOS 16-bit FAT (up to 32M)" );
        hash[ 0x05 ] << Info( "Extended", "Extended DOS 3.3+ extended partition" );
        hash[ 0x06 ] << Info( "FAT16", "DOS 3.31+ Large File System (16-bit FAT, over 32M)" );
        hash[ 0x07 ] << Info( "NTFS", "WindowsNT NTFS" );
        hash[ 0x07 ] << Info( "HPFS", "OS/2 HPFS" );
        hash[ 0x07 ] << Info( "Unix", "Advanced Unix" );
        hash[ 0x07 ] << Info( "QNX", "QNX QNX" );
        hash[ 0x08 ] << Info( "OS/2", "OS/2 (v1.0-1.3 only)" );
        hash[ 0x08 ] << Info( "AIX", "AIX bootable partition, SplitDrive" );
        hash[ 0x08 ] << Info( "Commodore", "Commodore Commodore DOS" );
        hash[ 0x08 ] << Info( "DELL", "DELL DELL partition spanning multiple drives" );
        hash[ 0x09 ] << Info( "Coherent", "Coherent Coherent filesystem" );
        hash[ 0x09 ] << Info( "AIX", "AIX AIX data partition" );
        hash[ 0x0A ] << Info( "OPUS", "OPUS OPUS" );
        hash[ 0x0A ] << Info( "Coherent", "Coherent Coherent swap partition" );
        hash[ 0x0A ] << Info( "Boot Manager", "OS/2 OS/2 Boot Manager" );
        hash[ 0x0B ] << Info( "FAT32", "Windows95 with 32-bit FAT" );
        hash[ 0x0C ] << Info( "FAT32 (LBA)", "Windows95 with 32-bit FAT (using LBA-mode INT 13 extensions)" );
        hash[ 0x0E ] << Info( "FAT16 (LBA)", "VFAT logical-block-addressable VFAT (same as 06h but using LBA)" );
        hash[ 0x0F ] << Info( "Extended (LBA)", "Extended LBA Extended partition (same as 05h but using LBA)" );
        hash[ 0x10 ] << Info( "OPUS", "OPUS OPUS" );
        hash[ 0x11 ] << Info( "FAT12 Boot Manager", "FAT12 OS/2 Boot Manager hidden 12-bit FAT partition" );
        hash[ 0x12 ] << Info( "Compaq", "Compaq Compaq Diagnostics partition" );
        hash[ 0x14 ] << Info( "FAT16 Boot Manager", "FAT16 OS/2 Boot Manager hidden sub-32M 16-bit FAT partition" );
        hash[ 0x16 ] << Info( "FAT16 Boot Manager", "FAT16 OS/2 Boot Manager hidden over-32M 16-bit FAT partition" );
        hash[ 0x17 ] << Info( "HPFS Boot Manager", "OS/2 OS/2 Boot Manager hidden HPFS partition" );
        hash[ 0x17 ] << Info( "NTFS", "NTFS hidden NTFS partition" );
        hash[ 0x18 ] << Info( "", "ASTSuspend AST special Windows swap file (\"Zero-Volt Suspend\" partition)" );
        hash[ 0x19 ] << Info( "", "Willowtech Willowtech Photon coS" );
        hash[ 0x1B ] << Info( "FAT32", "Windows hidden Windows95 FAT32 partition" );
        hash[ 0x1C ] << Info( "FAT32 (LBA)", "Windows hidden Windows95 FAT32 partition (LBA-mode)" );
        hash[ 0x1E ] << Info( "VFAT (BLA)", "Windows hidden LBA VFAT partition" );
        hash[ 0x20 ] << Info( "", "Willowsoft Willowsoft Overture File System (OFS1)" );
        hash[ 0x21 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x21 ] << Info( "", "FSo2" );
        hash[ 0x23 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x24 ] << Info( "NEC", "NEC MS-DOS 3.x" );
        hash[ 0x25 ] << Info( "WBFS", "Wii Backup File System" ); // Not official, just took a free place to set it.
        hash[ 0x26 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x31 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x33 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x34 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x36 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x38 ] << Info( "", "Theos" );
        hash[ 0x3C ] << Info( "PM", "PowerQuest PartitionMagic recovery partition" );
        hash[ 0x40 ] << Info( "", "VENIX 80286" );
        hash[ 0x41 ] << Info( "", "Personal RISC Boot" );
        hash[ 0x41 ] << Info( "", "PowerPC boot partition" );
        hash[ 0x42 ] << Info( "LDM", "Windows Logical Disk Manager" );
        hash[ 0x42 ] << Info( "SFS", "SFS(Secure File System) by Peter Gutmann" );
        hash[ 0x45 ] << Info( "", "EUMEL/Elan" );
        hash[ 0x46 ] << Info( "", "EUMEL/Elan" );
        hash[ 0x47 ] << Info( "", "EUMEL/Elan" );
        hash[ 0x48 ] << Info( "", "EUMEL/Elan" );
        hash[ 0x4F ] << Info( "", "Oberon Oberon boot/data partition" );
        hash[ 0x50 ] << Info( "", "OnTrack Disk Manager, read-only partition" );
        hash[ 0x51 ] << Info( "", "OnTrack Disk Manager, read/write partition" );
        hash[ 0x51 ] << Info( "Novell", "NOVELL" );
        hash[ 0x52 ] << Info( "CP/M", "CP/M" );
        hash[ 0x52 ] << Info( "", "Microport System V/386" );
        hash[ 0x53 ] << Info( "", "OnTrack Disk Manager, write-only partition???" );
        hash[ 0x54 ] << Info( "", "OnTrack Disk Manager (DDO)" );
        hash[ 0x55 ] << Info( "", "EZ-Drive EZ-Drive (see also INT 13/AH=FFh\"EZ-Drive\")" );
        hash[ 0x56 ] << Info( "", "GoldenBow GoldenBow VFeature" );
        hash[ 0x5C ] << Info( "", "Priam Priam EDISK" );
        hash[ 0x61 ] << Info( "", "SpeedStor" );
        hash[ 0x63 ] << Info( "Unix", "UnixSysV Unix SysV/386, 386/ix" );
        hash[ 0x63 ] << Info( "BSD", "Mach Mach, MtXinu BSD 4.3 on Mach" );
        hash[ 0x63 ] << Info( "HURD", "GNU-HURD GNU HURD" );
        hash[ 0x64 ] << Info( "Novell", "Novell Novell NetWare 286" );
        hash[ 0x64 ] << Info( "", "SpeedStore SpeedStore" );
        hash[ 0x65 ] << Info( "Novell", "Novell NetWare (3.11)" );
        hash[ 0x67 ] << Info( "Novell", "Novell" );
        hash[ 0x68 ] << Info( "Novell", "Novell" );
        hash[ 0x69 ] << Info( "NSS", "Novell NSS Volume" );
        hash[ 0x70 ] << Info( "DS", "DiskSecure DiskSecure Multi-Boot" );
        hash[ 0x71 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x73 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x74 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x75 ] << Info( "PC/IX", "PC/IX PC/IX" );
        hash[ 0x76 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0x7E ] << Info( "F.I.X.", "F.I.X. F.I.X." );
        hash[ 0x80 ] << Info( "Minix", "Minix Minix v1.1 - 1.4a" );
        hash[ 0x81 ] << Info( "Minix", "Minix Minix v1.4b+" );
        hash[ 0x81 ] << Info( "Linux", "Linux Linux" );
        hash[ 0x81 ] << Info( "", "Mitac Mitac Advanced Disk Manager" );
        hash[ 0x82 ] << Info( "Linux", "Linux/Swap Linux Swap partition" );
        hash[ 0x82 ] << Info( "", "Prime Prime" );
        hash[ 0x82 ] << Info( "Solaris", "Solaris Solaris (Unix)" );
        hash[ 0x83 ] << Info( "Linux", "Linux Linux native file system (ext2fs/xiafs)" );
        hash[ 0x84 ] << Info( "", "DOS OS/2-renumbered type 04h partition (hiding DOS C: drive)" );
        hash[ 0x85 ] << Info( "Linux", "Linux Linux EXT" );
        hash[ 0x86 ] << Info( "FAT16", "FAT16 FAT16 volume/stripe set (Windows NT)" );
        hash[ 0x87 ] << Info( "HPFS", "HPFS HPFS Fault-Tolerant mirrored partition" );
        hash[ 0x87 ] << Info( "NTFS", "NTFS NTFS volume/stripe set" );
        hash[ 0x8E ] << Info( "LVM", "Linux Logical Volume Manager" );
        hash[ 0x93 ] << Info( "", "Amoeba Amoeba file system" );
        hash[ 0x94 ] << Info( "", "Amoeba Amoeba bad block table" );
        hash[ 0x98 ] << Info( "", "Datalight Datalight ROM-DOS SuperBoot" );
        hash[ 0x99 ] << Info( "", "Mylex Mylex EISA SCSI" );
        hash[ 0xA0 ] << Info( "", "Phoenix Phoenix NoteBIOS Power Management \"Save-to-Disk\" partition" );
        hash[ 0xA1 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xA3 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xA4 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xA5 ] << Info( "FreeBSD", "FreeBSD FreeBSD, BSD/386" );
        hash[ 0xA6 ] << Info( "OpenBSD", "OpenBSD OpenBSD" );
        hash[ 0xA7 ] << Info( "USF", "Apple Rhapsody UFS" );
        hash[ 0xA8 ] << Info( "UFS", "Apple UFS" );
        hash[ 0xA9 ] << Info( "NetBSD", "NetBSD NetBSD (http://www.netbsd.org/)" );
        hash[ 0xAB ] << Info( "Boot", "Apple Boot" );
        hash[ 0xAE ] << Info( "Encryped", "Apple Encrypted" );
        hash[ 0xAF ] << Info( "HFS", "Apple HFS" );
        hash[ 0xB1 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xB3 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xB4 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xB6 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xB6 ] << Info( "FAT16", "Windows Windows NT mirror set (master), FAT16 file system" );
        hash[ 0xB7 ] << Info( "", "BSDI BSDI file system (secondarily swap)" );
        hash[ 0xB7 ] << Info( "NTFS", "Windows Windows NT mirror set (master), NTFS file system" );
        hash[ 0xB8 ] << Info( "", "BSDI BSDI swap partition (secondarily file system)" );
        hash[ 0xBE ] << Info( "", "Solaris Solaris boot partition" );
        hash[ 0xC0 ] << Info( "", "CTOS CTOS" );
        hash[ 0xC0 ] << Info( "", "DR-DOS DR DOS/DR-DOS/Novell DOS secured partition" );
        hash[ 0xC1 ] << Info( "", "DR-DOS6.0 DR DOS 6.0 LOGIN.EXE-secured 12-bit FAT partition" );
        hash[ 0xC4 ] << Info( "", "DR-DOS6.0 DR DOS 6.0 LOGIN.EXE-secured 16-bit FAT partition" );
        hash[ 0xC6 ] << Info( "", "DR-DOS6.0 DR DOS 6.0 LOGIN.EXE-secured Huge partition" );
        hash[ 0xC6 ] << Info( "", "corrupted corrupted FAT16 volume/stripe set (Windows NT)" );
        hash[ 0xC6 ] << Info( "FAT16", "Windows Windows NT mirror set (slave), FAT16 file system" );
        hash[ 0xC7 ] << Info( "Boot", "Syrinx Syrinx Boot" );
        hash[ 0xC7 ] << Info( "NTFS", "corrupted corrupted NTFS volume/stripe set" );
        hash[ 0xC7 ] << Info( "NTFS", "Windows Windows NT mirror set (slave), NTFS file system" );
        hash[ 0xCB ] << Info( "FAT32", "DR-DOS Reserved for DR DOS/DR-DOS/OpenDOS secured FAT32" );
        hash[ 0xCC ] << Info( "FAT32 (LBA)", "DR-DOS Reserved for DR DOS/DR-DOS secured FAT32 (LBA)" );
        hash[ 0xCE ] << Info( "FAT16 (LBA)", "DR-DOS Reserved for DR DOS/DR-DOS secured FAT16 (LBA)" );
        hash[ 0xD0 ] << Info( "FAT12", "Multiuser Multiuser DOS secured FAT12" );
        hash[ 0xD1 ] << Info( "FAT12", "Old-FAT12 Old Multiuser DOS secured FAT12" );
        hash[ 0xD4 ] << Info( "FAT16", "Old-FAT16 Old Multiuser DOS secured FAT16 (<= 32M)" );
        hash[ 0xD5 ] << Info( "Extended", "Old-Ext Old Multiuser DOS secured extended partition" );
        hash[ 0xD6 ] << Info( "FAT16", "Old-FAT16 Old Multiuser DOS secured FAT16 (> 32M)" );
        hash[ 0xD8 ] << Info( "CP/M-86", "CP/M-86 CP/M-86" );
        hash[ 0xDB ] << Info( "CP/M", "CP/M CP/M, Concurrent CP/M, Concurrent DOS" );
        hash[ 0xDB ] << Info( "CTOS", "CTOS CTOS (Convergent Technologies OS)" );
        hash[ 0xE1 ] << Info( "Extended", "SpeedStor SpeedStor 12-bit FAT extended partition" );
        hash[ 0xE2 ] << Info( "", "DOS DOS read-only (Florian Painke's XFDISK 1.0.4)" );
        hash[ 0xE3 ] << Info( "", "DOS DOS read-only" );
        hash[ 0xE3 ] << Info( "", "Storage Storage Dimensions" );
        hash[ 0xE4 ] << Info( "Extended", "SpeedStor SpeedStor 16-bit FAT extended partition" );
        hash[ 0xE5 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xE6 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xEB ] << Info( "BFS", "BeOS BeOS BFS (BFS1)" );
        hash[ 0xF1 ] << Info( "", "Storage Storage Dimensions" );
        hash[ 0xF2 ] << Info( "", "DOS DOS 3.3+ secondary partition" );
        hash[ 0xF3 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xF4 ] << Info( "", "SpeedStor SpeedStor" );
        hash[ 0xF4 ] << Info( "", "Storage Storage Dimensions" );
        hash[ 0xF5 ] << Info( "", "Prologue Prologue" );
        hash[ 0xF6 ] << Info( "", "[reserved] officially listed as reserved" );
        hash[ 0xFB ] << Info( "VMware", "VMWARE vmware partition" );
        hash[ 0xFD ] << Info( "Linux", "Linux RAID" );
        hash[ 0xFE ] << Info( "", "LANstep LANstep" );
        hash[ 0xFE ] << Info( "PS/2-IML", "PS/2-IML IBM PS/2 IML (Initial Microcode Load) partition" );
        hash[ 0xFF ] << Info( "Xenix", "Xenix Xenix bad block table" );
        //hash[ 0xFM ] << Info( "VMware", "VMware VMware raw partition" );
    }

    QStringList values;

    foreach ( const Info& info, hash.value( id ) ) {
        values << ( full ? info.second : info.first );
    }

    return values.isEmpty() ? QObject::tr( QT_TRANSLATE_NOOP( "pPartition", "Unknown FS" ) ) : values.join( ", " ).replace( "_", " " );
}


code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : Fresh Library
** FileName  : pPartition.h
** Date      : 2011-02-20T00:41:35
** License   : LGPL v3
** Home Page : http://bettercodes.org/projects/fresh
** Comment   : Fresh Library is a Qt 4 extension library providing set of new core & gui classes.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Leser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This package 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#ifndef PPARTITION_H
#define PPARTITION_H

/*!
    \file pPartition.h
    \brief An object that represent a partition on the system.
    \author Filipe Azevedo aka Nox P\@sNox <pasnox@gmail.com>
*/

#include <QVariant>
#include <QDateTime>

/*!
    \ingroup Core
    \class pPartition
    \brief An object that represent a partition on the system.
*/
class pPartition {
public:
    /*! This enum defines the differents types of device. */
    enum Type {
        Device, /*!< Generic device. */
        Disc /*!< CdRom / DVDRom / BluRay device. */
    };

    /*! This enum defines the differents types of property. */
    enum Property {
        Label, /*!< The partition label. */
        DevicePath, /*!< The device path like /dev/sda1, C:\... */
        FileSystem, /*!< The file system name. */
        TotalSize, /*!< The total size. */
        UsedSize, /*!< The used size. */
        FreeSize, /*!< The free size. */
        MountPoints, /*!< The mount points. */
        //DeviceType,
        DeviceVendor, /*!< The device vendor */
        DeviceModel, /*!< The device model. */
        FileSystemId, /*!< The file system id. */
        LastCheck, /*!< The last date time the partition was checked. */
        DisplayText, /*!< The display text. */
        LastProperty = DisplayText /*!< The last available property. */
    };

    /*!
        Create a partition for device at \a devicePath. The device validity is checked according to \a checkValidity beefore setting the internal property.
    */
    pPartition( const QString& devicePath = QString::null, bool checkValidity = true );
    /*!
        Check if \a other is same partition as this. The test is only done against the device path.
    */
    bool operator==( const pPartition& other ) const;
    /*!
        Set the properties map.
    */
    void setProperties( const QVariantMap& properties );
    /*!
        Return the properties map.
    */
    QVariantMap properties() const;
    /*!
        Return the content of the property \a property.
    */
    QVariant property( pPartition::Property property ) const;
    /*!
        Return the content of the property \a property. This allow to query non standard properties.
    */
    QVariant property( const QString& property ) const;
    /*!
        Update the partitions sizes. The used spaces is computed by the formula: total -free.
    */
    void updateSizes( qint64 total, qint64 free );
    /*!
        Return true if the partition is valid else false.
    */
    bool isValid() const;
    /*!
        Return true if the partition is a custom one else a false one.
        A partition is custom if it's internal device path is equal to the device path property.
        A non custom partition has its internal device path to null which is differnt than the device path property..
    */
    bool isCustom() const;
    /*!
        Return the device path, the property is queried first and if it's empty it return the internal device path.
    */
    QString devicePath() const;
    /*!
        Check is the partition \a devicePath is a WBFS partition.
    */
    static bool isWBFSPartition( const QString& devicePath );
    /*!
        Return true if the partition \a devicePath is a valid partition.
    */
    static bool isValidDevicePath( const QString& devicePath );
    /*!
        Return the file system name from the partition \a id.
        The device \a type is checked.
        Some Ids can represent differents kinds of file system, in this case \a full will return the concatened of all possible choice, else only the first one.
    */
    static QString fileSystemIdToString( qint64 id, pPartition::Type type = pPartition::Device, bool full = false );

protected:
    QVariantMap mProperties;
    QString mDevicePath;

    void updateLastChecked();
    QString generateDisplayText() const;
    QString value( const QString& key ) const;
};

typedef QList<pPartition> pPartitionList;

#endif // PPARTITION_H


code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : Fresh Library
** FileName  : pPartitionModel.cpp
** Date      : 2011-02-20T00:41:35
** License   : LGPL v3
** Home Page : http://bettercodes.org/projects/fresh
** Comment   : Fresh Library is a Qt 4 extension library providing set of new core & gui classes.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Leser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This package 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "pPartitionModel.h"

#include <FreshCore/pCoreUtils>

#include <QDebug>

pPartitionModel::pPartitionModel( QObject* parent )
    : QAbstractTableModel( parent )
{
    mData = 0;
    platformInit();
}

pPartitionModel::~pPartitionModel()
{
    platformDeInit();
}

int pPartitionModel::columnCount( const QModelIndex& parent ) const
{
    return parent.isValid() ? 0 : pPartition::LastProperty +1;
}

QVariant pPartitionModel::data( const QModelIndex& index, int role ) const
{
    if ( !index.isValid() ||
        index.row() < 0 || index.row() >= rowCount( index.parent() ) ||
        index.column() < 0 || index.column() >= columnCount( index.parent() ) ) {
        return QVariant();
    }

    const pPartition& partition = mPartitions[ index.row() ];

    switch ( role ) {
        case Qt::DecorationRole: {
            if ( index.column() == pPartition::Label ) {
            }

            break;
        }
        case Qt::DisplayRole: {
            switch ( index.column() ) {
                case pPartition::Label:
                case pPartition::DevicePath:
                case pPartition::FileSystem:
                case pPartition::MountPoints:
                case pPartition::DeviceVendor:
                case pPartition::DeviceModel:
                case pPartition::DisplayText:
                    return partition.property( pPartition::Property( index.column() ) );
                case pPartition::FileSystemId:
                    return QString::number( partition.property( pPartition::Property( index.column() ) ).toLongLong(), 16 ).toUpper().prepend( "0x" );
                case pPartition::TotalSize:
                case pPartition::UsedSize:
                case pPartition::FreeSize:
                    return pCoreUtils::fileSizeToString( partition.property( pPartition::Property( index.column() ) ).toLongLong() );
                case pPartition::LastCheck:
                    return partition.property( pPartition::LastCheck ).toDateTime().toString( Qt::SystemLocaleShortDate );
            }

            break;
        }
        case Qt::ToolTipRole: {
            QStringList tooltip;

            for ( int i = 0; i < columnCount(); i++ ) {
                tooltip << QString( "%1: %2" )
                    .arg( headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString() )
                    .arg( data( index.sibling( index.row(), i ), Qt::DisplayRole ).toString() )
                    ;
            }

            return tooltip.join( "
" );
            break;
        }
    }

    return QVariant();
}

int pPartitionModel::rowCount( const QModelIndex& parent ) const
{
    return parent.isValid() ? 0 : mPartitions.count();
}

QVariant pPartitionModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
    if ( section >= 0 && section < columnCount() && orientation == Qt::Horizontal ) {
        switch ( role ) {
            case Qt::DisplayRole:
            case Qt::ToolTipRole: {
                switch ( section ) {
                    case pPartition::Label:
                        return tr( "Label" );
                    case pPartition::DevicePath:
                        return tr( "Path" );
                    case pPartition::FileSystem:
                        return tr( "File System" );
                    case pPartition::MountPoints:
                        return tr( "Mount Points" );
                    case pPartition::DeviceVendor:
                        return tr( "Vendor" );
                    case pPartition::DeviceModel:
                        return tr( "Model" );
                    case pPartition::FileSystemId:
                        return tr( "File System Id" );
                    case pPartition::DisplayText:
                        return tr( "Display Text" );
                    case pPartition::TotalSize:
                        return tr( "Size" );
                    case pPartition::UsedSize:
                        return tr( "Used" );
                    case pPartition::FreeSize:
                        return tr( "Free" );
                    case pPartition::LastCheck:
                        return tr( "Last Check" );
                }
            }
        }
    }

    return QAbstractTableModel::headerData( section, orientation, role );
}

bool pPartitionModel::insertRow( int row, const QModelIndex& parent )
{
    const pPartition partition( QString::null );
    const int index = mPartitions.indexOf( partition );

    if ( index == -1 && !parent.isValid() ) {
        beginInsertRows( parent, row, row );
        mPartitions << partition;
        endInsertRows();

        return true;
    }

    return false;
}

bool pPartitionModel::insertRows( int row, int count, const QModelIndex& parent )
{
    if ( count > 1 || parent.isValid() ) {
        return false;
    }

    return insertRow( row, parent );
}

pPartition pPartitionModel::partition( const QModelIndex& index ) const
{
    return mPartitions.value( index.row() );
}

QModelIndex pPartitionModel::index( const pPartition& partition, int column ) const
{
    const int id = mPartitions.indexOf( partition );
    return QAbstractTableModel::index( id, column, QModelIndex() );
}

void pPartitionModel::addPartition( const QString& partition )
{
    updatePartition( pPartition( partition ) );
}

void pPartitionModel::addPartitions( const QStringList& partitions )
{
    foreach ( const QString& partition, partitions ) {
        addPartition( partition );
    }
}

void pPartitionModel::updatePartition( const pPartition& partition )
{
    if ( !partition.isValid() ) {
        return;
    }

    const int id = mPartitions.indexOf( partition );

    if ( id != -1 ) {
        const QModelIndex index = QAbstractTableModel::index( id, 0, QModelIndex() );
        mPartitions[ id ] = partition;

        emit dataChanged( index.sibling( index.row(), 0 ), index.sibling( index.row(), columnCount( index.parent() ) ) );
    }
    else {
        beginInsertRows( QModelIndex(), mPartitions.count(), mPartitions.count() );
        mPartitions << partition;
        endInsertRows();
    }
}

void pPartitionModel::removePartition( const QString& partition )
{
    const int id = mPartitions.indexOf( pPartition( partition, false ) );

    if ( id != -1 ) {
        beginRemoveRows( QModelIndex(), id, id );
        mPartitions.removeAt( id );
        endRemoveRows();
    }
}

pPartitionList pPartitionModel::partitions() const
{
    return mPartitions;
}

QStringList pPartitionModel::customPartitions() const
{
    QStringList custom;

    foreach ( const pPartition& partition, mPartitions ) {
        if ( partition.isCustom() ) {
            custom << partition.devicePath();
        }
    }

    return custom;
}

void pPartitionModel::dump() const
{
    for ( int y = 0; y < rowCount(); y++ ) {
        QStringList entries;

        for ( int x = 0; x < columnCount(); x++ ) {
            entries << QAbstractTableModel::index( y, x ).data().toString();
        }

        qWarning() << entries.join( "\t" );
    }
}

void pPartitionModel::update()
{
#if defined( Q_OS_MAC ) || defined( Q_OS_WIN ) || defined( Q_OS_LINUX )
    platformUpdate();
#else
    const QModelIndexList oldIndexes = persistentIndexList();
    pPartitionList partitions = this->partitions();
    QHash<int, int> mapping;
    QModelIndexList newIndexes;

    // manually added partitions
    for ( int i = 0; i < mPartitions.count(); i++ ) {
        const pPartition& partition = mPartitions[ i ];

        if ( !partitions.contains( partition ) && partition.isValid() ) {
            partitions << partition;
        }
    }

    // build mapping
    for ( int i = 0; i < mPartitions.count(); i++ ) {
        const pPartition& partition = mPartitions[ i ];
        mapping[ i ] = partitions.indexOf( partition );
    }

    emit layoutAboutToBeChanged();

    foreach ( const QModelIndex& idx, oldIndexes ) {
        const int i = idx.row();

        newIndexes << QAbstractTableModel::index( mapping[ i ], idx.column(), idx.parent()  );
    }

    mPartitions = partitions;
    changePersistentIndexList( oldIndexes, newIndexes );

    emit layoutChanged();
#endif
}


code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : Fresh Library
** FileName  : pPartitionModel.h
** Date      : 2011-02-20T00:41:35
** License   : LGPL v3
** Home Page : http://bettercodes.org/projects/fresh
** Comment   : Fresh Library is a Qt 4 extension library providing set of new core & gui classes.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Leser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This package 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#ifndef PPARTITIONMODEL_H
#define PPARTITIONMODEL_H

/*!
    \file pPartitionModel.h
    \brief A model presenting the available partitions.
    \author Filipe Azevedo aka Nox P\@sNox <pasnox@gmail.com>
*/

#include <QAbstractTableModel>

#include "pPartition.h"

/*!
    \ingroup Core
    \class pPartitionModel
    \brief A model presenting the available partitions.
*/
class pPartitionModel : public QAbstractTableModel
{
    Q_OBJECT
    friend class PartitionComboBox;

public:
    /*!
        Create an instance of the model having \a parent as parent.
    */
    pPartitionModel( QObject* parent = 0 );
    /*!
        Destroys the model instance.
    */
    virtual ~pPartitionModel();
    /*!
        Reimplemented.
    */
    virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const;
    /*!
        Reimplemented.
    */
    virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
    /*!
        Reimplemented.
    */
    virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
    /*!
        Reimplemented.
    */
    virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
    /*!
        Reimplemented.
    */
    virtual bool insertRow( int row, const QModelIndex& parent = QModelIndex() );
    /*!
        Reimplemented.
    */
    virtual bool insertRows( int row, int count, const QModelIndex& parent = QModelIndex() );
    //virtual void  sort ( int column, Qt::SortOrder order = Qt::AscendingOrder )
    /*!
        Return the pPartition at \a index.
    */
    pPartition partition( const QModelIndex& index ) const;
    /*!
        Return the QModelIndex of \a partition for \a column.
    */
    QModelIndex index( const pPartition& partition, int column = 0 ) const;
    /*!
        Add \a partition if it does not already exists and is valid.
    */
    void addPartition( const QString& partition );
    /*!
        Add \a partitions if they are not exists and are valid.
    */
    void addPartitions( const QStringList& partitions );
    /*!
        Update \a partition.
    */
    void updatePartition( const pPartition& partition );
    /*!
        Remove \a partition.
    */
    void removePartition( const QString& partition );
    /*!
        Return the list of all partitions.
    */
    pPartitionList partitions() const;
    /*!
        Return the list of custom partitions.
        \see pPartition::isCustom().
    */
    QStringList customPartitions() const;

    void dump() const;

public slots:
    /*!
        Update the list of partitions.
        \note Linux and Mac OS X should not need this as they are automatically updated by listening the OS events.
    */
    void update();

protected:
    pPartitionList mPartitions;
    mutable void* mData;

    virtual void platformInit();
    virtual void platformDeInit();
    virtual void platformUpdate();
};

#endif // PPARTITIONMODEL_H


code:
/****************************************************************************
**
**      Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : Fresh Library
** FileName  : pPartitionModel_linux.cpp
** Date      : 2011-02-20T00:41:35
** License   : LGPL v3
** Home Page : http://bettercodes.org/projects/fresh
** Comment   : Fresh Library is a Qt 4 extension library providing set of new core & gui classes.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Leser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This package 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "pPartitionModel.h"

//http://svn.openpilot.org/browse/OpenPilot/trunk/ground/openpilotgcs/src/plugins/rawhid/usbmonitor.h?r=3021

#include <libudev.h>
#include <sys/statfs.h>

#include <QStringList>
#include <QFileInfo>
#include <QSocketNotifier>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusVariant>
#include <QDebug>

class DisksSession : public QObject
{
    Q_OBJECT

public:
    DisksSession( pPartitionModel* model )
        : QObject( model )
    {
        mModel = model;
        mContext = udev_new();
        mMonitor = udev_monitor_new_from_netlink( mContext, "udev" );

        if ( !mContext ) {
            qWarning( "%s: UDev not valid.", Q_FUNC_INFO );
            return;
        }

        if ( !mMonitor ) {
            qWarning( "%s: UDevMonitor not valid.", Q_FUNC_INFO );
            return;
        }

        udev_monitor_filter_add_match_subsystem_devtype( mMonitor, "block", NULL );
        udev_monitor_enable_receiving( mMonitor );

        mNotifier = new QSocketNotifier( udev_monitor_get_fd( mMonitor ), QSocketNotifier::Read, this );

        connect( mNotifier, SIGNAL( activated( int ) ), this, SLOT( deviceEventReceived() ) );

        start();
    }

    virtual ~DisksSession()
    {
        udev_monitor_unref( mMonitor );
        udev_unref( mContext );
    }

    pPartition createPartition( struct udev_device* device )
    {
        struct udev_list_entry* entries = udev_device_get_properties_list_entry( device );
        struct udev_list_entry* entry = 0;
        pPartition partition;
        QVariantMap properties;

        udev_list_entry_foreach( entry, entries ) {
            const QString name = udev_list_entry_get_name( entry );
            const QString value = QString::fromLocal8Bit( udev_device_get_property_value( device, name.toLocal8Bit().constData() ) );

            properties[ name ] = value;
        }

        if ( properties.contains( "UDISKS_PARTITION_TYPE" ) ) {
            properties[ "UDISKS_PARTITION_TYPE" ] = properties[ "UDISKS_PARTITION_TYPE" ].toString().toLongLong( 0, 16 );
        }

        const QString devName = QFileInfo( properties[ "DEVNAME" ].toString() ).fileName();
        QDBusMessage question = QDBusMessage::createMethodCall( "org.freedesktop.UDisks", QString( "/org/freedesktop/UDisks/devices/%1" ).arg( devName ), "org.freedesktop.DBus.Properties", "Get" );
        question << "org.freedesktop.UDisks.Device" << "DeviceMountPaths";
        QDBusMessage answer = QDBusConnection::systemBus().call( question, QDBus::Block, 1 );
        QStringList mountPoints;

        foreach ( const QVariant& variant, answer.arguments() ) {
            const QStringList values = variant.value<QDBusVariant>().variant().toStringList();

            if ( !values.isEmpty() ) {
                mountPoints << values;
            }
        }

        if ( pPartition::isWBFSPartition( properties[ "DEVNAME" ].toString() ) ) {
            properties[ "UDISKS_PARTITION_TYPE" ] = 0x25;
            properties[ "ID_FS_TYPE" ] = pPartition::fileSystemIdToString( 0x25 );
        }

        qint64 total = properties.value( "UDISKS_PARTITION_SIZE", -1 ).toLongLong();
        qint64 free = -1;

        if ( !mountPoints.isEmpty() ) {
            struct statfs stats;

            if ( statfs( qPrintable( mountPoints.first() ), &stats ) == 0 ) {
                /*const qint64 total = stats.f_blocks *stats.f_bsize;
                partition.used = total -( stats.f_bfree *stats.f_bsize );
                partition.free = partition.total -partition.used;*/

                total = stats.f_blocks *stats.f_bsize;
                free = stats.f_bfree *stats.f_bsize;
            }

            properties[ "UDISKS_PARTITION_MOUNT_POINTS" ] = mountPoints;
        }

        properties[ "REMOVABLE" ] = "0";

        // Check removable attr
        struct udev_device* parent = 0;

        if ( properties[ "DEVTYPE" ] == "partition" ) {
            parent = udev_device_get_parent( device );
        }
        else if ( properties[ "DEVTYPE" ] == "disk" ) {
            parent = device; // disk without partitions
        }

        if ( parent != 0 ) {
            const char* value = udev_device_get_sysattr_value( parent, "removable" );

            if ( value ) {
                properties[ "REMOVABLE" ] = QString::fromLocal8Bit( value );
            }
        }

        partition.setProperties( properties );
        partition.updateSizes( total, free );

        return partition;
    }

protected:
    void start()
    {
        struct udev_enumerate* enumerate  = udev_enumerate_new( mContext );

        if ( !enumerate ) {
            qWarning( "%s: Can't enumerate.", Q_FUNC_INFO );
            return;
        }

        udev_enumerate_add_match_subsystem( enumerate, "block" );
        udev_enumerate_scan_devices( enumerate );

        struct udev_device* device = 0;
        struct udev_list_entry* entries = udev_enumerate_get_list_entry( enumerate );
        struct udev_list_entry* entry = 0;

        udev_list_entry_foreach( entry, entries ) {
            device = udev_device_new_from_syspath( mContext, udev_list_entry_get_name( entry ) );

            if ( !device ) {
                continue;
            }

            diskAppeared( device );

            udev_device_unref( device );
        }

        udev_enumerate_unref( enumerate );
    }

protected slots:
    void deviceEventReceived()
    {
        struct udev_device* device = udev_monitor_receive_device( mMonitor );

        if ( device ) {
            const QString action = QString( udev_device_get_action( device ) );
            const QString devtype = QString( udev_device_get_devtype( device ) );

            if ( action == "add" ) {
                diskAppeared( device );
            }
            else if ( action == "change" ) {
                diskChanged( device );
            }
            else if ( action == "remove" ){
                diskDisappeared( device );
            }
            else {
                qWarning() << Q_FUNC_INFO << "------- Got Device Event" <<  "type" << devtype << " - action" << action;
            }

            udev_device_unref( device );
        }
        else {
            qWarning( "%s: No Device. An error occured.", Q_FUNC_INFO );
        }
    }

    void diskAppeared( struct udev_device* device )
    {
        const pPartition partition = createPartition( device );

        if ( partition.properties()[ "DEVTYPE" ] == "partition"
            || ( partition.properties()[ "ID_TYPE" ] == "cd"
                && partition.properties()[ "ID_FS_USAGE" ] == "filesystem" ) ) {
            mModel->updatePartition( partition );
        }
    }

    void diskChanged( struct udev_device* device )
    {
        diskAppeared( device );
    }

    void diskDisappeared( struct udev_device* device )
    {
        const QString devicePath = QString::fromLocal8Bit( udev_device_get_property_value( device, "DEVNAME" ) );
        mModel->removePartition( devicePath );
    }

protected:
    pPartitionModel* mModel;
    udev* mContext;
    udev_monitor* mMonitor;
    QSocketNotifier* mNotifier;
};

void pPartitionModel::platformInit()
{
    emit layoutAboutToBeChanged();
    mData = new DisksSession( this );
    emit layoutChanged();
}

void pPartitionModel::platformDeInit()
{
    delete (DisksSession*)mData;
}

void pPartitionModel::platformUpdate()
{
    // Code commented as the linux implementation has the concept of live auto update, thanks to UDev librarie :)
    /*const QStringList partitions = customPartitions();

    emit layoutAboutToBeChanged();
    delete (DisksSession*)mData;
    mPartitions.clear();
    foreach ( const QString& partition, partitions ) {
        mPartitions << pPartition( partition );
    }
    mData = new DisksSession( this );
    emit layoutChanged();*/
}

#include "pPartitionModel_linux.moc"


code:
/****************************************************************************
**
** 		Created using Monkey Studio IDE v1.8.4.0 (1.8.4.0)
** Authors   : Filipe Azevedo aka Nox P@sNox <pasnox@gmail.com>
** Project   : Fresh Library
** FileName  : pPartitionModel_mac.cpp
** Date      : 2011-02-20T00:41:35
** License   : LGPL v3
** Home Page : http://bettercodes.org/projects/fresh
** Comment   : Fresh Library is a Qt 4 extension library providing set of new core & gui classes.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Leser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This package 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "pPartitionModel.h"

/*
http://www.datarecovery.com/hexcodes.asp
http://stackoverflow.com/questions/1515068/list-all-drives-partitions-and-get-dev-rdisc-device-with-cocoa
*/

#import <DiskArbitration/DiskArbitration.h>
#import <CoreServices/CoreServices.h>

#include <FreshCore/pMacHelpers>

#include <QStringList>
#include <QDebug>

class DADisksSession
{
public:
	DADisksSession( pPartitionModel* model )
	{
		mModel = model;

		// init session
		mSession = DASessionCreate( kCFAllocatorDefault );
		DARegisterDiskAppearedCallback( mSession, 0/*all disks*/, diskAppeared, mModel );
		DARegisterDiskDescriptionChangedCallback( mSession, 0/*all disks*/, 0/*all keys*/, diskChanged, mModel );
		DARegisterDiskDisappearedCallback( mSession, 0/*all disks*/, diskDisappeared, mModel );
		DASessionScheduleWithRunLoop( mSession, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
	}

	virtual ~DADisksSession()
	{
		// deinit session
		DASessionUnscheduleFromRunLoop( mSession, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
		CFRelease( mSession );
	}

	static pPartition createPartition( DADiskRef disk )
	{
		const CFDictionaryRef dict = DADiskCopyDescription( disk );
		QVariantMap properties = pMacHelpers::toQVariantMap( dict );
		pPartition partition;

		CFRelease( dict );

		// set properties on partitions only
		if ( !properties.value( "DAMediaWhole" ).toBool() ) {
			const QString devicePath = QString( "/dev/%1" ).arg( properties.value( "DAMediaBSDName" ).toString() );

			if ( pPartition::isWBFSPartition( devicePath ) ) {
				properties[ "DAVolumeKindId" ] = 0x25;
				properties[ "DAVolumeKind" ] = pPartition::fileSystemIdToString( 0x25 );
			}

			FSVolumeRefNum volume;
			qint64 total = properties.value( "DAMediaSize", -1 ).toLongLong();
			qint64 free = -1;

			// get volume infos, like total bytes, free bytes...
			if ( FSGetVolumeForDADisk( disk, &volume ) == noErr ) {
				FSVolumeInfo volumeInfo;

				bzero( (void*)&volumeInfo, sizeof(volumeInfo));

				/*qint64 major = properties.value( "DAMediaBSDMajor" ).toLongLong();
				qint64 minor = properties.value( "DAMediaBSDMinor" ).toLongLong();

				qWarning() << "-----";
				QStringList test;
				test << QString( "%1%2" ).arg( major, 0, 16 ).arg( minor, 0, 16 ).toUpper().prepend( "0x" );
				test << QString( "%1" ).arg( major +minor, 0, 16 ).toUpper().prepend( "0x" );
				test << QString( "%1" ).arg( major, 0, 16 ).toUpper().prepend( "0x" );

				qWarning()
					<< properties.value( "DAVolumeKind" ).toString().toUpper()
					<< properties.value( "DAMediaContent" ).toString().toUpper()
					<< test;*/

				if ( properties[ "DAVolumeKindId" ] != 0x25 && FSGetVolumeInfo( volume, 0, 0, kFSVolInfoSizes | kFSVolInfoFSInfo, &volumeInfo, 0, 0 ) == noErr ) {
					properties[ "DAVolumeKindId" ] = volumeInfo.filesystemID == 0 ? 0xAF : volumeInfo.filesystemID;
					total = volumeInfo.totalBytes;
					free = volumeInfo.freeBytes;
				}
			}

			partition.setProperties( properties );
			partition.updateSizes( total, free );
		}

		return partition;
	}

	static void diskAppeared( DADiskRef disk, void* context )
	{
		pPartitionModel* model = static_cast<pPartitionModel*>( context );
		model->updatePartition( createPartition( disk ) );
	}

	static void diskChanged( DADiskRef disk, CFArrayRef keys, void* context )
	{
		Q_UNUSED( keys );
		pPartitionModel* model = static_cast<pPartitionModel*>( context );
		model->updatePartition( createPartition( disk ) );
	}

	static void diskDisappeared( DADiskRef disk, void* context )
	{
		pPartitionModel* model = static_cast<pPartitionModel*>( context );
		model->removePartition( QString( "/dev/%1" ).arg( DADiskGetBSDName( disk ) ) );
	}

protected:
	pPartitionModel* mModel;
	DASessionRef mSession;
};

void pPartitionModel::platformInit()
{
	emit layoutAboutToBeChanged();
	mData = new DADisksSession( this );
	emit layoutChanged();
}

void pPartitionModel::platformDeInit()
{
	delete (DADisksSession*)mData;
}

void pPartitionModel::platformUpdate()
{
	// Code commented as the mac implementation has the concept of live auto update, thanks Disk Arbitration framework :)
	/*const QStringList partitions = customPartitions();

	emit layoutAboutToBeChanged();
	delete (DADisksSession*)mData;
	mPartitions.clear();
	foreach ( const QString& partition, partitions ) {
		mPartitions << pPartition( partition );
	}
	mData = new DADisksSession( this );
	emit layoutChanged();*/
}