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_win.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/pWinHelpers>

#include <qt_windows.h>
#include <QStringList>
#include <QDebug>

#include <tchar.h>

void pPartitionModel::platformInit()
{
    emit layoutAboutToBeChanged();
    mData = 0;
    emit layoutChanged();
}

void pPartitionModel::platformDeInit()
{
}

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();*/

    const QStringList partitions = customPartitions();

    emit layoutAboutToBeChanged();

    mPartitions.clear();
    foreach ( const QString& partition, partitions ) {
        mPartitions << pPartition( partition );
    }

    mData = 0;

    TCHAR drives[ MAX_PATH +1 ];
    GetLogicalDriveStrings( MAX_PATH +1, drives );
    TCHAR* drive = drives;

    while ( *drive ) {
        /*HRESULT hr = GetDriveType( drive );

        switch ( hr ) {
            case DRIVE_UNKNOWN:
                partition.device = pPartition::Unknown;
                break;
            case DRIVE_NO_ROOT_DIR:
                partition.device = pPartition::NotMounted;
                continue;
            case DRIVE_REMOVABLE:
                partition.device = pPartition::Removable;
                break;
            case DRIVE_FIXED:
                partition.device = pPartition::Fixed;
                break;
            case DRIVE_REMOTE:
                partition.device = pPartition::Remote;
                break;
            case DRIVE_CDROM:
                partition.device = pPartition::CdRom;
                break;
            case DRIVE_RAMDISK:
                partition.device = pPartition::RamDisk;
                break;
        }*/

        TCHAR volume[ MAX_PATH +1 ] = {0}; // volumne name
        TCHAR fs[ MAX_PATH +1 ] = {0}; // file system type ( FAT/NTFS...)
        ulong serial; // partition serial
        ulong max; // max filename length
        ulong flags; // flags
        qint64 available = -1; // user quota
        qint64 total = -1; // system total
        qint64 free = -1; // system free

        if ( GetVolumeInformation(
            drive,
            volume,
            MAX_PATH +1,
            &serial,
            &max,
            &flags,
            fs,
            MAX_PATH +1 ) ) {
            if ( !GetDiskFreeSpaceEx(
                drive,
                (PULARGE_INTEGER)&available,
                (PULARGE_INTEGER)&total,
                (PULARGE_INTEGER)&free ) ) {
                qWarning( "GetDiskFreeSpaceEx Error: %s", qPrintable( TCHARToQString( drive ) ) );
            }
        }
        else {
            qWarning( "GetVolumeInformation Error: %s", qPrintable( TCHARToQString( drive ) ) );
        }

        pPartition partition;
        QVariantMap properties;

        properties[ "LABEL" ] = TCHARToQString( volume );
        properties[ "DEVICE" ] = TCHARToQString( drive );
        properties[ "MOUNT_POINTS" ] = TCHARToQString( drive );
        properties[ "FS_TYPE" ] = TCHARToQString( fs );
        properties[ "FS_TYPE_ID" ] = 0;

        if ( pPartition::isWBFSPartition( TCHARToQString( drive ) ) ) {
            properties[ "FS_TYPE_ID" ] = 0x25;
            properties[ "FS_TYPE" ] = pPartition::fileSystemIdToString( 0x25 );
        }

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

        mPartitions << partition;

        drive = &drive[ _tcslen( drive ) +1 ];
    }

    emit layoutChanged();
}


code:
PictureFlow version 0.1.0 (initial release)

  basic functionality similar to Apple's Cover Flow
  optimized software renderer
  optional blur effect for the reflection
  single code base for Qt 4/3/2

repo_name: CYBERDEViL/qwbfsmanager

license: unknown


code:
  PictureFlow - animated image show
  http://pictureflow.googlecode.com

Copyright and License
---------------------

  Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
  Copyright (C) 2008 Ariya Hidayat (ariya@kde.org)

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.


code:
/*
  PictureFlow - animated image show widget
  http://pictureflow.googlecode.com

  Copyright (C) 2009 Ariya Hidayat (ariya@kde.org)
  Copyright (C) 2008 Ariya Hidayat (ariya@kde.org)
  Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

#include <QtGui>

#include "pictureflow.h"

QStringList findFiles(const QString& path = QString())
{
    QStringList files;

    QDir dir = QDir::current();
    if (!path.isEmpty())
        dir = QDir(path);

    dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
    QFileInfoList list = dir.entryInfoList();
    for (int i = 0; i < list.size(); ++i)
        files += dir.absoluteFilePath(list.at(i).fileName());

    return files;
}

class Browser: public PictureFlow
{
public:
    Browser(): PictureFlow() {
        setWindowTitle("PictureFlow");
    }

    void keyPressEvent(QKeyEvent* event) {
        if (event->key() == Qt::Key_Escape || event->key() == Qt::Key_Enter ||
                event->key() == Qt::Key_Return) {
            event->accept();
            close();
        }

        // checking the speed of rendering
        if (event->key() == Qt::Key_F10)
            if (event->modifiers() == Qt::AltModifier) {
                qDebug("benchmarking.... please wait");
                const int blit_count = 10;

                QTime stopwatch;
                stopwatch.start();
                for (int i = 0; i < blit_count; i++) {
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                    render(); repaint(); QApplication::flush(); QApplication::syncX();
                }
                QString msg;
                int elapsed = stopwatch.elapsed();
                if (elapsed > 0)
                    msg = QString("FPS: %1").arg(blit_count * 10 * 1000.0 / elapsed);
                else
                    msg = QString("Too fast. Increase blit_count");
                setWindowTitle(msg);
                event->accept();
                return;
            }

        // for debugging only: Alt+F11 cycles the reflection effect
        if (event->key() == Qt::Key_F11)
            if (event->modifiers() == Qt::AltModifier) {
                qDebug("changing reflection effect...");
                switch (reflectionEffect()) {
                    //case NoReflection:      setReflectionEffect(PlainReflection); break;
                case PlainReflection:   setReflectionEffect(BlurredReflection); break;
                case BlurredReflection: setReflectionEffect(PlainReflection); break;
                default:                setReflectionEffect(PlainReflection); break;
                }
                event->accept();
                return;
            }

        PictureFlow::keyPressEvent(event);
    }
};

int main(int argc, char ** argv)
{
    QApplication* app = new QApplication(argc, argv);
    Browser* w = new Browser;

#if defined(_WS_QWS) || defined(Q_WS_QWS)
    w->showFullScreen();
    int ww = w->width();
    int wh = w->height();
    int dim = (ww > wh) ? wh : ww;
    dim = dim * 3 / 4;
    w->setSlideSize(QSize(3*dim / 5, dim));
#else
    w->setSlideSize(QSize(3*40, 5*40));
    w->resize(750, 270);
#endif

    QStringList files = (argc > 1) ? findFiles(QString(argv[1])) : findFiles();

    QImage img;
    for (int i = 0; i < (int)files.count(); i++)
        if (img.load(files[i]))
            w->addSlide(img);

    w->setCenterIndex(w->slideCount() / 2);
    w->setBackgroundColor(Qt::white);
    w->show();

    app->connect(app, SIGNAL(lastWindowClosed()), app, SLOT(quit()));
    int result = app->exec();

    delete w;
    delete app;

    return result;
}


code:
/*
  PictureFlow - animated image show widget
  http://pictureflow.googlecode.com

  Copyright (C) 2009 Ariya Hidayat (ariya@kde.org)
  Copyright (C) 2008 Ariya Hidayat (ariya@kde.org)
  Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

#include "pictureflow.h"

// detect Qt version
#if QT_VERSION < 0x040300
#error PictureFlow widgets need Qt 4.3 or later
#endif

#include <QApplication>
#include <QCache>
#include <QHash>
#include <QImage>
#include <QKeyEvent>
#include <QPainter>
#include <QPixmap>
#include <QTimer>
#include <QVector>
#include <QWidget>

// for fixed-point arithmetic, we need minimum 32-bit long
// long long (64-bit) might be useful for multiplication and division
typedef long PFreal;
#define PFREAL_SHIFT 10
#define PFREAL_ONE (1 << PFREAL_SHIFT)

#define IANGLE_MAX 1024
#define IANGLE_MASK 1023

inline PFreal fmul(PFreal a, PFreal b)
{
    return ((long long)(a))*((long long)(b)) >> PFREAL_SHIFT;
}

inline PFreal fdiv(PFreal num, PFreal den)
{
    long long p = (long long)(num) << (PFREAL_SHIFT * 2);
    long long q = p / (long long)den;
    long long r = q >> PFREAL_SHIFT;

    return r;
}

inline PFreal fsin(int iangle)
{
    // warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed!
    static const PFreal tab[] = {
        3,    103,    202,    300,    394,    485,    571,    652,
        726,    793,    853,    904,    947,    980,   1004,   1019,
        1023,   1018,   1003,    978,    944,    901,    849,    789,
        721,    647,    566,    479,    388,    294,    196,     97,
        -4,   -104,   -203,   -301,   -395,   -486,   -572,   -653,
        -727,   -794,   -854,   -905,   -948,   -981,  -1005,  -1020,
        -1024,  -1019,  -1004,   -979,   -945,   -902,   -850,   -790,
        -722,   -648,   -567,   -480,   -389,   -295,   -197,    -98,
        3
    };

    while (iangle < 0)
        iangle += IANGLE_MAX;
    iangle &= IANGLE_MASK;

    int i = (iangle >> 4);
    PFreal p = tab[i];
    PFreal q = tab[(i+1)];
    PFreal g = (q - p);
    return p + g *(iangle - i*16) / 16;
}

inline PFreal fcos(int iangle)
{
    return fsin(iangle + (IANGLE_MAX >> 2));
}

/* ----------------------------------------------------------

PictureFlowState stores the state of all slides, i.e. all the necessary
information to be able to render them.

PictureFlowAnimator is responsible to move the slides during the
transition between slides, to achieve the effect similar to Cover Flow,
by changing the state.

PictureFlowSoftwareRenderer (or PictureFlowOpenGLRenderer) is
the actual 3-d renderer. It should render all slides given the state
(an instance of PictureFlowState).

Instances of all the above three classes are stored in
PictureFlowPrivate.

------------------------------------------------------- */

struct SlideInfo {
    int slideIndex;
    int angle;
    PFreal cx;
    PFreal cy;
    int blend;
};

class PictureFlowState
{
public:
    PictureFlowState();
    ~PictureFlowState();

    void reposition();
    void reset();

    QRgb backgroundColor;
    int slideWidth;
    int slideHeight;
    PictureFlow::ReflectionEffect reflectionEffect;
    QVector<QImage*> slideImages;

    int angle;
    int spacing;
    PFreal offsetX;
    PFreal offsetY;

    SlideInfo centerSlide;
    QVector<SlideInfo> leftSlides;
    QVector<SlideInfo> rightSlides;
    int centerIndex;
};

class PictureFlowAnimator
{
public:
    PictureFlowAnimator();
    PictureFlowState* state;

    void start(int slide);
    void stop(int slide);
    void update();

    int target;
    int step;
    int frame;
    QTimer animateTimer;
};

class PictureFlowAbstractRenderer
{
public:
    PictureFlowAbstractRenderer(): state(0), dirty(false), widget(0) {}
    virtual ~PictureFlowAbstractRenderer() {}

    PictureFlowState* state;
    bool dirty;
    QWidget* widget;

    virtual void init() = 0;
    virtual void paint() = 0;
};

class PictureFlowSoftwareRenderer: public PictureFlowAbstractRenderer
{
public:
    PictureFlowSoftwareRenderer();
    ~PictureFlowSoftwareRenderer();

    virtual void init();
    virtual void paint();

private:
    QSize size;
    QRgb bgcolor;
    int effect;
    QImage buffer;
    QVector<PFreal> rays;
    QImage* blankSurface;
    QCache<int, QImage> surfaceCache;
    QHash<int, QImage*> imageHash;

    void render();
    void renderSlides();
    QRect renderSlide(const SlideInfo &slide, int col1 = -1, int col2 = -1);
    QImage* surface(int slideIndex);
};

// ------------- PictureFlowState ---------------------------------------

PictureFlowState::PictureFlowState():
        backgroundColor(0), slideWidth(150), slideHeight(200),
        reflectionEffect(PictureFlow::BlurredReflection), centerIndex(0)
{
}

PictureFlowState::~PictureFlowState()
{
    for (int i = 0; i < (int)slideImages.count(); i++)
        delete slideImages[i];
}

// readjust the settings, call this when slide dimension is changed
void PictureFlowState::reposition()
{
    angle = 70 * IANGLE_MAX / 360;  // approx. 70 degrees tilted

    offsetX = slideWidth / 2 * (PFREAL_ONE - fcos(angle));
    offsetY = slideWidth / 2 * fsin(angle);
    offsetX += slideWidth * PFREAL_ONE;
    offsetY += slideWidth * PFREAL_ONE / 4;
    spacing = 40;
}

// adjust slides so that they are in "steady state" position
void PictureFlowState::reset()
{
    centerSlide.angle = 0;
    centerSlide.cx = 0;
    centerSlide.cy = 0;
    centerSlide.slideIndex = centerIndex;
    centerSlide.blend = 256;

    leftSlides.resize(6);
    for (int i = 0; i < (int)leftSlides.count(); i++) {
        SlideInfo& si = leftSlides[i];
        si.angle = angle;
        si.cx = -(offsetX + spacing * i * PFREAL_ONE);
        si.cy = offsetY;
        si.slideIndex = centerIndex - 1 - i;
        si.blend = 256;
        if (i == (int)leftSlides.count() - 2)
            si.blend = 128;
        if (i == (int)leftSlides.count() - 1)
            si.blend = 0;
    }

    rightSlides.resize(6);
    for (int i = 0; i < (int)rightSlides.count(); i++) {
        SlideInfo& si = rightSlides[i];
        si.angle = -angle;
        si.cx = offsetX + spacing * i * PFREAL_ONE;
        si.cy = offsetY;
        si.slideIndex = centerIndex + 1 + i;
        si.blend = 256;
        if (i == (int)rightSlides.count() - 2)
            si.blend = 128;
        if (i == (int)rightSlides.count() - 1)
            si.blend = 0;
    }
}

// ------------- PictureFlowAnimator  ---------------------------------------

PictureFlowAnimator::PictureFlowAnimator():
        state(0), target(0), step(0), frame(0)
{
}

void PictureFlowAnimator::start(int slide)
{
    target = slide;
    if (!animateTimer.isActive() && state) {
        step = (target < state->centerSlide.slideIndex) ? -1 : 1;
        animateTimer.start(30);
    }
}

void PictureFlowAnimator::stop(int slide)
{
    step = 0;
    target = slide;
    frame = slide << 16;
    animateTimer.stop();
}

void PictureFlowAnimator::update()
{
    if (!animateTimer.isActive())
        return;
    if (step == 0)
        return;
    if (!state)
        return;

    int speed = 16384 / 4;

#if 1
    // deaccelerate when approaching the target
    const int max = 2 * 65536;

    int fi = frame;
    fi -= (target << 16);
    if (fi < 0)
        fi = -fi;
    fi = qMin(fi, max);

    int ia = IANGLE_MAX * (fi - max / 2) / (max * 2);
    speed = 512 + 16384 * (PFREAL_ONE + fsin(ia)) / PFREAL_ONE;
#endif

    frame += speed * step;

    int index = frame >> 16;
    int pos = frame & 0xffff;
    int neg = 65536 - pos;
    int tick = (step < 0) ? neg : pos;
    PFreal ftick = (tick * PFREAL_ONE) >> 16;

    if (step < 0)
        index++;

    if (state->centerIndex != index) {
        state->centerIndex = index;
        frame = index << 16;
        state->centerSlide.slideIndex = state->centerIndex;
        for (int i = 0; i < (int)state->leftSlides.count(); i++)
            state->leftSlides[i].slideIndex = state->centerIndex - 1 - i;
        for (int i = 0; i < (int)state->rightSlides.count(); i++)
            state->rightSlides[i].slideIndex = state->centerIndex + 1 + i;
    }

    state->centerSlide.angle = (step * tick * state->angle) >> 16;
    state->centerSlide.cx = -step * fmul(state->offsetX, ftick);
    state->centerSlide.cy = fmul(state->offsetY, ftick);

    if (state->centerIndex == target) {
        stop(target);
        state->reset();
        return;
    }

    for (int i = 0; i < (int)state->leftSlides.count(); i++) {
        SlideInfo& si = state->leftSlides[i];
        si.angle = state->angle;
        si.cx = -(state->offsetX + state->spacing * i * PFREAL_ONE + step * state->spacing * ftick);
        si.cy = state->offsetY;
    }

    for (int i = 0; i < (int)state->rightSlides.count(); i++) {
        SlideInfo& si = state->rightSlides[i];
        si.angle = -state->angle;
        si.cx = state->offsetX + state->spacing * i * PFREAL_ONE - step * state->spacing * ftick;
        si.cy = state->offsetY;
    }

    if (step > 0) {
        PFreal ftick = (neg * PFREAL_ONE) >> 16;
        state->rightSlides[0].angle = -(neg * state->angle) >> 16;
        state->rightSlides[0].cx = fmul(state->offsetX, ftick);
        state->rightSlides[0].cy = fmul(state->offsetY, ftick);
    } else {
        PFreal ftick = (pos * PFREAL_ONE) >> 16;
        state->leftSlides[0].angle = (pos * state->angle) >> 16;
        state->leftSlides[0].cx = -fmul(state->offsetX, ftick);
        state->leftSlides[0].cy = fmul(state->offsetY, ftick);
    }

    // must change direction ?
    if (target < index) if (step > 0)
            step = -1;
    if (target > index) if (step < 0)
            step = 1;

    // the first and last slide must fade in/fade out
    int nleft = state->leftSlides.count();
    int nright = state->rightSlides.count();
    int fade = pos / 256;

    for (int index = 0; index < nleft; index++) {
        int blend = 256;
        if (index == nleft - 1)
            blend = (step > 0) ? 0 : 128 - fade / 2;
        if (index == nleft - 2)
            blend = (step > 0) ? 128 - fade / 2 : 256 - fade / 2;
        if (index == nleft - 3)
            blend = (step > 0) ? 256 - fade / 2 : 256;
        state->leftSlides[index].blend = blend;
    }
    for (int index = 0; index < nright; index++) {
        int blend = (index < nright - 2) ? 256 : 128;
        if (index == nright - 1)
            blend = (step > 0) ? fade / 2 : 0;
        if (index == nright - 2)
            blend = (step > 0) ? 128 + fade / 2 : fade / 2;
        if (index == nright - 3)
            blend = (step > 0) ? 256 : 128 + fade / 2;
        state->rightSlides[index].blend = blend;
    }

}

// ------------- PictureFlowSoftwareRenderer ---------------------------------------

PictureFlowSoftwareRenderer::PictureFlowSoftwareRenderer():
        PictureFlowAbstractRenderer(), size(0, 0), bgcolor(0), effect(-1), blankSurface(0)
{
}

PictureFlowSoftwareRenderer::~PictureFlowSoftwareRenderer()
{
    surfaceCache.clear();
    buffer = QImage();
    delete blankSurface;
}

void PictureFlowSoftwareRenderer::paint()
{
    if (!widget)
        return;

    if (widget->size() != size)
        init();

    if (state->backgroundColor != bgcolor) {
        bgcolor = state->backgroundColor;
        surfaceCache.clear();
    }

    if ((int)(state->reflectionEffect) != effect) {
        effect = (int)state->reflectionEffect;
        surfaceCache.clear();
    }

    if (dirty)
        render();

    QPainter painter(widget);
    painter.drawImage(QPoint(0, 0), buffer);
}

void PictureFlowSoftwareRenderer::init()
{
    if (!widget)
        return;

    surfaceCache.clear();
    blankSurface = 0;

    size = widget->size();
    int ww = size.width();
    int wh = size.height();
    int w = (ww + 1) / 2;
    int h = (wh + 1) / 2;

    buffer = QImage(ww, wh, QImage::Format_RGB32);
    buffer.fill(bgcolor);

    rays.resize(w*2);
    for (int i = 0; i < w; i++) {
        PFreal gg = ((PFREAL_ONE >> 1) + i * PFREAL_ONE) / (2 * h);
        rays[w-i-1] = -gg;
        rays[w+i] = gg;
    }

    dirty = true;
}

// TODO: optimize this with lookup tables
static QRgb blendColor(QRgb c1, QRgb c2, int blend)
{
    int r = qRed(c1) * blend / 256 + qRed(c2) * (256 - blend) / 256;
    int g = qGreen(c1) * blend / 256 + qGreen(c2) * (256 - blend) / 256;
    int b = qBlue(c1) * blend / 256 + qBlue(c2) * (256 - blend) / 256;
    return qRgb(r, g, b);
}

static QImage* prepareSurface(const QImage* slideImage, int w, int h, QRgb bgcolor,
                              PictureFlow::ReflectionEffect reflectionEffect)
{
    Qt::TransformationMode mode = Qt::SmoothTransformation;
    QImage img = slideImage->scaled(w, h, Qt::IgnoreAspectRatio, mode);

    // slightly larger, to accomodate for the reflection
    int hs = h * 2;
    int hofs = h / 3;

    // offscreen buffer: black is sweet
    QImage* result = new QImage(hs, w, QImage::Format_RGB32);
    result->fill(bgcolor);

    // transpose the image, this is to speed-up the rendering
    // because we process one column at a time
    // (and much better and faster to work row-wise, i.e in one scanline)
    for (int x = 0; x < w; x++)
        for (int y = 0; y < h; y++)
            result->setPixel(hofs + y, x, img.pixel(x, y));

    if (reflectionEffect != PictureFlow::NoReflection) {
        // create the reflection
        int ht = hs - h - hofs;
        int hte = ht;
        for (int x = 0; x < w; x++)
            for (int y = 0; y < ht; y++) {
                QRgb color = img.pixel(x, img.height() - y - 1);
                result->setPixel(h + hofs + y, x, blendColor(color, bgcolor, 128*(hte - y) / hte));
            }

        if (reflectionEffect == PictureFlow::BlurredReflection) {
            // blur the reflection everything first
            // Based on exponential blur algorithm by Jani Huhtanen
            QRect rect(hs / 2, 0, hs / 2, w);
            rect &= result->rect();

            int r1 = rect.top();
            int r2 = rect.bottom();
            int c1 = rect.left();
            int c2 = rect.right();

            int bpl = result->bytesPerLine();
            int rgba[4];
            unsigned char* p;

            // how many times blur is applied?
            // for low-end system, limit this to only 1 loop
            for (int loop = 0; loop < 2; loop++) {
                for (int col = c1; col <= c2; col++) {
                    p = result->scanLine(r1) + col * 4;
                    for (int i = 0; i < 3; i++)
                        rgba[i] = p[i] << 4;

                    p += bpl;
                    for (int j = r1; j < r2; j++, p += bpl)
                        for (int i = 0; i < 3; i++)
                            p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
                }

                for (int row = r1; row <= r2; row++) {
                    p = result->scanLine(row) + c1 * 4;
                    for (int i = 0; i < 3; i++)
                        rgba[i] = p[i] << 4;

                    p += 4;
                    for (int j = c1; j < c2; j++, p += 4)
                        for (int i = 0; i < 3; i++)
                            p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
                }

                for (int col = c1; col <= c2; col++) {
                    p = result->scanLine(r2) + col * 4;
                    for (int i = 0; i < 3; i++)
                        rgba[i] = p[i] << 4;

                    p -= bpl;
                    for (int j = r1; j < r2; j++, p -= bpl)
                        for (int i = 0; i < 3; i++)
                            p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
                }

                for (int row = r1; row <= r2; row++) {
                    p = result->scanLine(row) + c2 * 4;
                    for (int i = 0; i < 3; i++)
                        rgba[i] = p[i] << 4;

                    p -= 4;
                    for (int j = c1; j < c2; j++, p -= 4)
                        for (int i = 0; i < 3; i++)
                            p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
                }
            }

            // overdraw to leave only the reflection blurred (but not the actual image)
            for (int x = 0; x < w; x++)
                for (int y = 0; y < h; y++)
                    result->setPixel(hofs + y, x, img.pixel(x, y));
        }
    }

    return result;
}

QImage* PictureFlowSoftwareRenderer::surface(int slideIndex)
{
    if (!state)
        return 0;
    if (slideIndex < 0)
        return 0;
    if (slideIndex >= (int)state->slideImages.count())
        return 0;

    int key = slideIndex;

    QImage* img = state->slideImages.at(slideIndex);
    bool empty = img ? img->isNull() : true;
    if (empty) {
        surfaceCache.remove(key);
        imageHash.remove(slideIndex);
        if (!blankSurface) {
            int sw = state->slideWidth;
            int sh = state->slideHeight;

            QImage img = QImage(sw, sh, QImage::Format_RGB32);

            QPainter painter(&img);
            QPoint p1(sw*4 / 10, 0);
            QPoint p2(sw*6 / 10, sh);
            QLinearGradient linearGrad(p1, p2);
            linearGrad.setColorAt(0, Qt::black);
            linearGrad.setColorAt(1, Qt::white);
            painter.setBrush(linearGrad);
            painter.fillRect(0, 0, sw, sh, QBrush(linearGrad));

            painter.setPen(QPen(QColor(64, 64, 64), 4));
            painter.setBrush(QBrush());
            painter.drawRect(2, 2, sw - 3, sh - 3);
            painter.end();

            blankSurface = prepareSurface(&img, sw, sh, bgcolor, state->reflectionEffect);
        }
        return blankSurface;
    }

    bool exist = imageHash.contains(slideIndex);
    if (exist)
        if (img == imageHash.find(slideIndex).value())
            if (surfaceCache.contains(key))
                return surfaceCache[key];

    QImage* sr = prepareSurface(img, state->slideWidth, state->slideHeight, bgcolor, state->reflectionEffect);
    surfaceCache.insert(key, sr);
    imageHash.insert(slideIndex, img);

    return sr;
}

// Renders a slide to offscreen buffer. Returns a rect of the rendered area.
// col1 and col2 limit the column for rendering.
QRect PictureFlowSoftwareRenderer::renderSlide(const SlideInfo &slide, int col1, int col2)
{
    int blend = slide.blend;
    if (!blend)
        return QRect();

    QImage* src = surface(slide.slideIndex);
    if (!src)
        return QRect();

    QRect rect(0, 0, 0, 0);

    int sw = src->height();
    int sh = src->width();
    int h = buffer.height();
    int w = buffer.width();

    if (col1 > col2) {
        int c = col2;
        col2 = col1;
        col1 = c;
    }

    col1 = (col1 >= 0) ? col1 : 0;
    col2 = (col2 >= 0) ? col2 : w - 1;
    col1 = qMin(col1, w - 1);
    col2 = qMin(col2, w - 1);

    int zoom = 100;
    int distance = h * 100 / zoom;
    PFreal sdx = fcos(slide.angle);
    PFreal sdy = fsin(slide.angle);
    PFreal xs = slide.cx - state->slideWidth * sdx / 2;
    PFreal ys = slide.cy - state->slideWidth * sdy / 2;
    PFreal dist = distance * PFREAL_ONE;

    int xi = qMax((PFreal)0, (w * PFREAL_ONE / 2) + fdiv(xs * h, dist + ys) >> PFREAL_SHIFT);
    if (xi >= w)
        return rect;

    bool flag = false;
    rect.setLeft(xi);
    for (int x = qMax(xi, col1); x <= col2; x++) {
        PFreal hity = 0;
        PFreal fk = rays[x];
        if (sdy) {
            fk = fk - fdiv(sdx, sdy);
            hity = -fdiv((rays[x] * distance - slide.cx + slide.cy * sdx / sdy), fk);
        }

        dist = distance * PFREAL_ONE + hity;
        if (dist < 0)
            continue;

        PFreal hitx = fmul(dist, rays[x]);
        PFreal hitdist = fdiv(hitx - slide.cx, sdx);

        int column = sw / 2 + (hitdist >> PFREAL_SHIFT);
        if (column >= sw)
            break;
        if (column < 0)
            continue;

        rect.setRight(x);
        if (!flag)
            rect.setLeft(x);
        flag = true;

        int y1 = h / 2;
        int y2 = y1 + 1;
        QRgb* pixel1 = (QRgb*)(buffer.scanLine(y1)) + x;
        QRgb* pixel2 = (QRgb*)(buffer.scanLine(y2)) + x;
        QRgb pixelstep = pixel2 - pixel1;

        int center = (sh / 2);
        int dy = dist / h;
        int p1 = center * PFREAL_ONE - dy / 2;
        int p2 = center * PFREAL_ONE + dy / 2;

        const QRgb *ptr = (const QRgb*)(src->scanLine(column));
        if (blend == 256)
            while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
                *pixel1 = ptr[p1 >> PFREAL_SHIFT];
                *pixel2 = ptr[p2 >> PFREAL_SHIFT];
                p1 -= dy;
                p2 += dy;
                y1--;
                y2++;
                pixel1 -= pixelstep;
                pixel2 += pixelstep;
            }
        else
            while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
                QRgb c1 = ptr[p1 >> PFREAL_SHIFT];
                QRgb c2 = ptr[p2 >> PFREAL_SHIFT];
                *pixel1 = blendColor(c1, bgcolor, blend);
                *pixel2 = blendColor(c2, bgcolor, blend);
                p1 -= dy;
                p2 += dy;
                y1--;
                y2++;
                pixel1 -= pixelstep;
                pixel2 += pixelstep;
            }
    }

    rect.setTop(0);
    rect.setBottom(h - 1);
    return rect;
}

void PictureFlowSoftwareRenderer::renderSlides()
{
    int nleft = state->leftSlides.count();
    int nright = state->rightSlides.count();

    QRect r = renderSlide(state->centerSlide);
    int c1 = r.left();
    int c2 = r.right();

    for (int index = 0; index < nleft; index++) {
        QRect rs = renderSlide(state->leftSlides[index], 0, c1 - 1);
        if (!rs.isEmpty())
            c1 = rs.left();
    }
    for (int index = 0; index < nright; index++) {
        QRect rs = renderSlide(state->rightSlides[index], c2 + 1, buffer.width());
        if (!rs.isEmpty())
            c2 = rs.right();
    }
}

// Render the slides. Updates only the offscreen buffer.
void PictureFlowSoftwareRenderer::render()
{
    buffer.fill(state->backgroundColor);
    renderSlides();
    dirty = false;
}

// -----------------------------------------

class PictureFlowPrivate
{
public:
    PictureFlowState* state;
    PictureFlowAnimator* animator;
    PictureFlowAbstractRenderer* renderer;
    QTimer triggerTimer;
};

PictureFlow::PictureFlow(QWidget* parent): QWidget(parent)
{
    d = new PictureFlowPrivate;

    d->state = new PictureFlowState;
    d->state->reset();
    d->state->reposition();

    d->renderer = new PictureFlowSoftwareRenderer;
    d->renderer->state = d->state;
    d->renderer->widget = this;
    d->renderer->init();

    d->animator = new PictureFlowAnimator;
    d->animator->state = d->state;
    QObject::connect(&d->animator->animateTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));

    QObject::connect(&d->triggerTimer, SIGNAL(timeout()), this, SLOT(render()));

    setAttribute(Qt::WA_StaticContents, true);
    setAttribute(Qt::WA_OpaquePaintEvent, true);
    setAttribute(Qt::WA_NoSystemBackground, true);

    setFocusPolicy(Qt::WheelFocus);
}

PictureFlow::~PictureFlow()
{
    delete d->renderer;
    delete d->animator;
    delete d->state;
    delete d;
}

int PictureFlow::slideCount() const
{
    return d->state->slideImages.count();
}

QColor PictureFlow::backgroundColor() const
{
    return QColor(d->state->backgroundColor);
}

void PictureFlow::setBackgroundColor(const QColor& c)
{
    d->state->backgroundColor = c.rgb();
    triggerRender();
}

QSize PictureFlow::slideSize() const
{
    return QSize(d->state->slideWidth, d->state->slideHeight);
}

void PictureFlow::setSlideSize(QSize size)
{
    d->state->slideWidth = size.width();
    d->state->slideHeight = size.height();
    d->state->reposition();
    triggerRender();
}

PictureFlow::ReflectionEffect PictureFlow::reflectionEffect() const
{
    return d->state->reflectionEffect;
}

void PictureFlow::setReflectionEffect(ReflectionEffect effect)
{
    d->state->reflectionEffect = effect;
    triggerRender();
}

QImage PictureFlow::slide(int index) const
{
    QImage* i = 0;
    if ((index >= 0) && (index < slideCount()))
        i = d->state->slideImages[index];
    return i ? QImage(*i) : QImage();
}

void PictureFlow::insertSlide(int index, const QImage& image)
{
    if ((index >= 0) && (index <= slideCount())) {
        int c = d->state->slideImages.count();
        d->state->slideImages.resize(c);
        d->state->slideImages.insert(index, new QImage(image));
        triggerRender();
    }
}

void PictureFlow::insertSlide(int index, const QPixmap& pixmap)
{
    insertSlide(index, pixmap.toImage());
}

void PictureFlow::addSlide(const QImage& image)
{
    int c = d->state->slideImages.count();
    d->state->slideImages.resize(c + 1);
    d->state->slideImages[c] = new QImage(image);
    triggerRender();
}

void PictureFlow::addSlide(const QPixmap& pixmap)
{
    addSlide(pixmap.toImage());
}

void PictureFlow::removeSlide(int index)
{
    int c = d->state->slideImages.count();
    if (index >= 0 && index < c) {
        d->state->slideImages.remove(index);
        triggerRender();
    }
}

void PictureFlow::setSlide(int index, const QImage& image)
{
    if ((index >= 0) && (index < slideCount())) {
        QImage* i = image.isNull() ? 0 : new QImage(image);
        delete d->state->slideImages[index];
        d->state->slideImages[index] = i;
        triggerRender();
    }
}

void PictureFlow::setSlide(int index, const QPixmap& pixmap)
{
    setSlide(index, pixmap.toImage());
}

int PictureFlow::centerIndex() const
{
    return d->state->centerIndex;
}

void PictureFlow::setCenterIndex(int index)
{
    index = qMin(index, slideCount() - 1);
    index = qMax(index, 0);
    d->state->centerIndex = index;
    d->state->reset();
    d->animator->stop(index);
    triggerRender();
}

void PictureFlow::clear()
{
    int c = d->state->slideImages.count();
    for (int i = 0; i < c; i++)
        delete d->state->slideImages[i];
    d->state->slideImages.resize(0);

    d->state->reset();
    triggerRender();
}

void PictureFlow::render()
{
    d->renderer->dirty = true;
    update();
}

void PictureFlow::triggerRender()
{
    d->triggerTimer.setSingleShot(true);
    d->triggerTimer.start(0);
}

void PictureFlow::showPrevious()
{
    int step = d->animator->step;
    int center = d->state->centerIndex;

    if (step > 0)
        d->animator->start(center);

    if (step == 0)
        if (center > 0)
            d->animator->start(center - 1);

    if (step < 0)
        d->animator->target = qMax(0, center - 2);
}

void PictureFlow::showNext()
{
    int step = d->animator->step;
    int center = d->state->centerIndex;

    if (step < 0)
        d->animator->start(center);

    if (step == 0)
        if (center < slideCount() - 1)
            d->animator->start(center + 1);

    if (step > 0)
        d->animator->target = qMin(center + 2, slideCount() - 1);
}

void PictureFlow::showSlide(int index)
{
    index = qMax(index, 0);
    index = qMin(slideCount() - 1, index);
    if (index == d->state->centerSlide.slideIndex)
        return;

    d->animator->start(index);
}

void PictureFlow::keyPressEvent(QKeyEvent* event)
{
    if (event->key() == Qt::Key_Left) {
        if (event->modifiers() == Qt::ControlModifier)
            showSlide(centerIndex() - 10);
        else
            showPrevious();
        event->accept();
        return;
    }

    if (event->key() == Qt::Key_Right) {
        if (event->modifiers() == Qt::ControlModifier)
            showSlide(centerIndex() + 10);
        else
            showNext();
        event->accept();
        return;
    }

    event->ignore();
}

void PictureFlow::mousePressEvent(QMouseEvent* event)
{
    const int midWidth = width() /2;
    const int midSlideWidth = slideSize().width() /2;

    if (event->x() > (midWidth + midSlideWidth))
        showNext();
    else if (event->x() < (midWidth - midSlideWidth))
        showPrevious();
}

void PictureFlow::wheelEvent(QWheelEvent* event)
{
    const int numDegrees = event->delta() / 8;
    const int numSteps = numDegrees / 15;

    if ( numSteps < 0 ) {
        showNext();
    }
    else if ( numSteps > 0 ) {
        showPrevious();
    }
}

void PictureFlow::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event);
    d->renderer->paint();
}

void PictureFlow::resizeEvent(QResizeEvent* event)
{
    triggerRender();
    QWidget::resizeEvent(event);
}

int PictureFlow::animatorStep() const
{
    return d->animator->step;
}

void PictureFlow::updateAnimation()
{
    int old_center = d->state->centerIndex;
    d->animator->update();
    triggerRender();
    if (d->state->centerIndex != old_center)
        emit centerIndexChanged(d->state->centerIndex);
}


code:
/*
  PictureFlow - animated image show widget
  http://pictureflow.googlecode.com

  Copyright (C) 2009 Ariya Hidayat (ariya@kde.org)
  Copyright (C) 2008 Ariya Hidayat (ariya@kde.org)
  Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

#ifndef PICTUREFLOW_H
#define PICTUREFLOW_H

#include <qwidget.h>

class PictureFlowPrivate;

/*!
  Class PictureFlow implements an image show widget with animation effect
  like Apple's CoverFlow (in iTunes and iPod). Images are arranged in form
  of slides, one main slide is shown at the center with few slides on
  the left and right sides of the center slide. When the next or previous
  slide is brought to the front, the whole slides flow to the right or
  the right with smooth animation effect; until the new slide is finally
  placed at the center.

 */
class PictureFlow : public QWidget
{
    Q_OBJECT

    Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
    Q_PROPERTY(QSize slideSize READ slideSize WRITE setSlideSize)
    Q_PROPERTY(int slideCount READ slideCount)
    Q_PROPERTY(int centerIndex READ centerIndex WRITE setCenterIndex)

public:

    enum ReflectionEffect {
        NoReflection,
        PlainReflection,
        BlurredReflection
    };

    /*!
      Creates a new PictureFlow widget.
    */
    PictureFlow(QWidget* parent = 0);

    /*!
      Destroys the widget.
    */
    ~PictureFlow();

    /*!
      Returns the background color.
    */
    QColor backgroundColor() const;

    /*!
      Sets the background color. By default it is black.
    */
    void setBackgroundColor(const QColor& c);

    /*!
      Returns the dimension of each slide (in pixels).
    */
    QSize slideSize() const;

    /*!
      Sets the dimension of each slide (in pixels).
    */
    void setSlideSize(QSize size);

    /*!
      Returns the total number of slides.
    */
    int slideCount() const;

    /*!
      Returns QImage of specified slide.
    */
    QImage slide(int index) const;

    /*!
      Returns the index of slide currently shown in the middle of the viewport.
    */
    int centerIndex() const;

    /*!
      Returns the effect applied to the reflection.
    */
    ReflectionEffect reflectionEffect() const;

    /*!
      Sets the effect applied to the reflection. The default is PlainReflection.
    */
    void setReflectionEffect(ReflectionEffect effect);

public slots:

    /*!
      Adds a new slide.
    */
    void addSlide(const QImage& image);

    /*!
      Adds a new slide.
    */
    void addSlide(const QPixmap& pixmap);

    /*!
      Inserts a new slide at given position.
    */
    void insertSlide(int index, const QImage& image);

    /*!
      Inserts a new slide at given position.
    */
    void insertSlide(int index, const QPixmap& pixmap);

    /*!
      Removes an existing slide.
    */
    void removeSlide(int index);

    /*!
      Sets an image for specified slide. If the slide already exists,
      it will be replaced.
    */
    void setSlide(int index, const QImage& image);

    /*!
      Sets a pixmap for specified slide. If the slide already exists,
      it will be replaced.
    */
    void setSlide(int index, const QPixmap& pixmap);

    /*!
      Sets slide to be shown in the middle of the viewport. No animation
      effect will be produced, unlike using showSlide.
    */
    void setCenterIndex(int index);

    /*!
      Clears all slides.
    */
    void clear();

    /*!
      Shows previous slide using animation effect.
    */
    void showPrevious();

    /*!
      Shows next slide using animation effect.
    */
    void showNext();

    /*!
      Go to specified slide using animation effect.
    */
    void showSlide(int index);

    /*!
      Rerender the widget. Normally this function will be automatically invoked
      whenever necessary, e.g. during the transition animation.
    */
    void render();

    /*!
      Schedules a rendering update. Unlike render(), this function does not cause
      immediate rendering.
    */
    void triggerRender();

signals:
    void centerIndexChanged(int index);

protected:
    void paintEvent(QPaintEvent *event);
    void keyPressEvent(QKeyEvent* event);
    void mousePressEvent(QMouseEvent* event);
    void wheelEvent(QWheelEvent* event);
    void resizeEvent(QResizeEvent* event);

    int animatorStep() const;

private slots:
    void updateAnimation();

private:
    PictureFlowPrivate* d;
};

#endif // PICTUREFLOW_H


code:
TARGET = pictureflow
TEMPLATE = app
HEADERS = pictureflow.h
SOURCES = pictureflow.cpp main.cpp


code:
import os
import sipconfig
from PyQt4 import pyqtconfig

config = pyqtconfig.Configuration()

# The name of the SIP build file generated by SIP and used by the build
# system.
build_file = "pictureflow.sbf"
sip_files_dir = "sip"
output_dir = "pictureflow"

if not os.path.exists(output_dir):
    os.mkdir(output_dir)

# Build the pictureflow library.
os.system("cd lib; qmake; make")

# Run SIP to generate the code.
command = " ".join(
    [config.sip_bin, "-c", output_dir, "-b", os.path.join(output_dir, build_file),
     "-I"+config.pyqt_sip_dir,
     "-I"+config.qt_inc_dir, config.pyqt_sip_flags,
     os.path.join(sip_files_dir, "pictureflowmod.sip")]
    )

print command
os.system(command)

# Create the Makefile.
makefile = pyqtconfig.QtGuiModuleMakefile(
    config, build_file, dir=output_dir
    )
makefile.extra_include_dirs.append(os.path.abspath(os.pardir))
makefile.extra_lib_dirs.append(os.path.abspath(os.curdir))
makefile.extra_lib_dirs.append(os.path.abspath("lib"))
makefile.extra_libs.append("pictureflow")

# Generate the Makefile itself.
config.pyqt_modules = config.pyqt_modules.split()
makefile.generate()
del config.pyqt_modules

sipconfig.ParentMakefile(
    configuration = config,
    subdirs = [output_dir]
    ).generate()


code:
CONFIG += static
TEMPLATE = lib
TARGET = pictureflow
HEADERS = ../../pictureflow.h
SOURCES = ../../pictureflow.cpp


code:
/*
  PictureFlow - animated image show widget
  http://pictureflow.googlecode.com

  Copyright (C) 2008 Ariya Hidayat (ariya@kde.org)
  Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

class PictureFlow : QWidget
{

%TypeHeaderCode
#include "pictureflow.h"
%End

public:

  enum ReflectionEffect
  {
    NoReflection,
    PlainReflection,
    BlurredReflection
  };

  PictureFlow(QWidget *parent /TransferThis/ = 0);
  ~PictureFlow();
  QColor backgroundColor() const;
  void setBackgroundColor(const QColor& c);
  QSize slideSize() const;
  void setSlideSize(QSize size);
  int slideCount() const;
  QImage slide(int index) const;
  int centerIndex() const;
  ReflectionEffect reflectionEffect() const;
  void setReflectionEffect(ReflectionEffect effect);

public slots:
  void addSlide(const QImage& image);
  void addSlide(const QPixmap& pixmap);
  void setSlide(int index, const QImage& image);
  void setSlide(int index, const QPixmap& pixmap);
  void setCenterIndex(int index);
  void clear();
  void showPrevious();
  void showNext();
  void showSlide(int index);
  void render();
  void triggerRender();

signals:
  void centerIndexChanged(int index);

protected:
  void paintEvent(QPaintEvent *event);
  void keyPressEvent(QKeyEvent* event);
  void mousePressEvent(QMouseEvent* event);
  void resizeEvent(QResizeEvent* event);
};


code:
%Module pictureflow 0

%Import QtCore/QtCoremod.sip
%Import QtGui/QtGuimod.sip

%Include pictureflow.sip


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  : Driver.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 "Driver.h"
#include "PartitionDiscHandle.h"
#include "models/Disc.h"

#include <libwbfs.h>

#include <ctime>

#include <QDir>
#include <QApplication>
#include <QDebug>

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

using namespace QWBFS;

#define WBFS_FILE_MINIMUM_SIZE 1024 *1024 *16

QMutex Driver::mMutex;
bool Driver::mForce = false;
QHash<QString, QWBFS::Partition::Handle> Driver::mHandles;
QHash<int, QString> Driver::mLanguages;
QHash<int, QString> Driver::mRegions;
QWBFS::Driver* Driver::mCurrentDriver = 0;

Driver::Driver( QObject* parent, const QWBFS::Partition::Handle& partitionHandle )
    : QObject( parent )
{
    mProperties = partitionHandle.properties();
    mHandle = partitionHandle;
    mHasCreatedHandle = !partitionHandle.isValid();

    init();
}

Driver::Driver( const QWBFS::Partition::Handle& partitionHandle )
    : QObject( 0 )
{
    mProperties = partitionHandle.properties();
    mHandle = partitionHandle;
    mHasCreatedHandle = !partitionHandle.isValid();

    init();
}

Driver::~Driver()
{
    close();
}

void Driver::init()
{
    if ( mRegions.isEmpty() && mLanguages.isEmpty() )
    {
        /*
            ASCII Hex Region
            A 41 All regions. System channels like the Mii channel use it.
            D 44 German-speaking regions. Only if separate versions exist, e.g. Zelda: A Link to the Past
            E 45 USA and other NTSC regions except Japan
            F 46 French-speaking regions. Only if separate versions exist, e.g. Zelda: A Link to the Past.
            J 4A Japan
            K 4B Korea
            L 4C PAL/World?
            P 50 Europe, Australia and other PAL regions
            Q 51 Korea with Japanese language.
            T 54 Korea with English language.
            X 58 Not a real region code. Homebrew Channel uses it, though.
        */

        /*
            WiiTDB Folder Game ID:

            E = US
            J = JA
            K = KO
            R = RU
            W = ZH

            ça c'est fixe, ça ne bouge pas, c'est toujours en fonction du game ID

            Pour les ID en P,D,F,I,S,H,X,Y,Z, on fait en fonction de la langue de l'utilisateur
            (donc celle de l'interface ou avec une option) et on utilise EN, FR, DE, ES, IT, NL, PT

            Si l'image n'est pas trouvée dans la langue de préférence, on essaye EN (sauf si la langue préférée est l'anglais bien sur)

            Si l'ID ne contient aucune de ces lettres c'est que c'est un jeu custom avec un ID qui n'est pas standard.

            Dans ce cas on essaye la langue préférée, puis EN, puis other en tout dernier.
        */

        // Regions
        mRegions.insert( 'A', "World" ); // All regions. System channels like the Mii channel use it.
        mRegions.insert( 'E', "NTSC-U" ); // USA and other NTSC regions except Japan.
        mRegions.insert( 'J', "NTSC-J" ); // Japan
        mRegions.insert( 'K', "NTSC-K" ); // Korea
        mRegions.insert( 'P', "PAL" ); // Europe, Australia and other PAL regions.
        mRegions.insert( 'W', "NTSC-T" ); // Taiwan
        mRegions.insert( 'R', "PAL-R" ); // Russia
        mRegions.insert( 'Q', "NTSC-K" ); // Korea with Japanese language.
        mRegions.insert( 'T', "NTSC-K" ); // Korea with English language.
        mRegions.insert( 'F', "PAL" ); // French-speaking regions. Only if separate versions exist, e.g. Zelda: A Link to the Past.
        mRegions.insert( 'D', "PAL" ); // German-speaking regions. Only if separate versions exist, e.g. Zelda: A Link to the Past.
        mRegions.insert( 'I', "PAL" ); // Italien-speaking regions. Only if separate versions exist.
        mRegions.insert( 'H', "PAL" ); // Dutch-speaking regions. Only if separate versions exist.
        mRegions.insert( 'S', "PAL" ); // Spanish-speaking regions. Only if separate versions exist.
        mRegions.insert( 'X', "PAL" ); // ??
        mRegions.insert( 'Y', "PAL" ); // ??
        mRegions.insert( 'Z', "PAL" ); // ??
        // Custom disc / Channels
        mRegions.insert( 'L', "CUSTOM" );
        mRegions.insert( 'M', "CUSTOM" );
        mRegions.insert( 'N', "CUSTOM" );

        // Languages
        /*mLanguages[ 'L' ] = QLatin1String( "EN" ); // Japanese Import to Europe, Australia and other PAL regions
        mLanguages[ 'M' ] = QLatin1String( "EN" ); // American Import to Europe, Australia and other PAL regions
        mLanguages[ 'N' ] = QLatin1String( "JA" ); // Japanese Import to USA and other NTSC regions*/

        mLanguages.insert( 'A', "EN" ); // All regions. System channels like the Mii channel use it.
        mLanguages.insert( 'E', "US" ); // USA and other NTSC regions except Japan.
        mLanguages.insert( 'J', "JA" ); // Japan
        mLanguages.insert( 'K', "KO" ); // Korea
        mLanguages.insert( 'R', "RU" ); // Russia
        mLanguages.insert( 'W', "ZH" ); // Taiwan
        /*mLanguages.insert( 'Q', "JA" ); // Korea with Japanese language.
        mLanguages.insert( 'T', "EN" ); // Korea with English language.
        mLanguages.insert( 'F', "FR" ); // French-speaking regions. Only if separate versions exist, e.g. Zelda: A Link to the Past.
        mLanguages.insert( 'D', "DE" ); // German-speaking regions. Only if separate versions exist, e.g. Zelda: A Link to the Past.
        mLanguages.insert( 'I', "IT" ); // Italian-speaking regions. Only if separate versions exist.
        mLanguages.insert( 'H', "NL" ); // Dutch-speaking regions. Only if separate versions exist.
        mLanguages.insert( 'S', "ES" ); // Spanish-speaking regions. Only if separate versions exist.*/

        //insert( 'P', "" ); // Europe, Australia and other PAL regions.
    }
}

void Driver::setPartition( const QString& partition )
{
    mProperties.partition = partition;
}

QString Driver::partition() const
{
    return mHandle.isValid() ? mHandle.partition() : mProperties.partition;
}

QWBFS::Partition::Handle Driver::handle() const
{
    return mHandle;
}

bool Driver::open()
{
    if ( isOpen() ) {
        close();
    }

    mHandle = getHandle( mProperties.partition, &mHasCreatedHandle );
    return isOpen();
}

void Driver::close()
{
    if ( !isOpen() ) {
        return;
    }

    if ( mHasCreatedHandle ) {
        mHasCreatedHandle = false;
        closeHandle( mHandle );
    }

    mHandle = QWBFS::Partition::Handle();
}

bool Driver::isOpen() const
{
    return mHandle.isValid();
}

bool Driver::format()
{
    if ( isOpen() ) {
        close();
    }

    QWBFS::Partition::Properties properties = mProperties;
    properties.reset = true;

    const QWBFS::Partition::Handle handle( properties );
    const QWBFS::Partition::Status status( handle );

    return handle.isValid() && status.size > 0;
}

int Driver::discCount() const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    return wbfs_count_discs( mHandle.ptr() );
}

int Driver::discInfo( int index, QWBFS::Model::Disc& disc ) const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    if ( index < 0 || index >= discCount() ) {
        return Driver::InvalidDiscIndex;
    }

    const int headerSize = 0x100;
    u8* header = (u8*)wbfs_ioalloc( headerSize );
    quint32 size;

    disc.origin = mHandle.partition();

    if ( wbfs_get_disc_info( mHandle.ptr(), index, header, headerSize, &size ) != 0 ) {
        wbfs_iofree( header );
        return Driver::DiscReadFailed;
    }

    disc.size = size *4ULL;
    discInfo( header, disc );
    wbfs_iofree( header );

    return Driver::Ok;
}

int Driver::discInfo( const QString& discId, QWBFS::Model::Disc& disc ) const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    const QWBFS::Partition::DiscHandle discHandle( mHandle, discId );

    if ( discHandle.isValid() ) {
        return discInfo( discHandle.index(), disc );
    }

    return Driver::InvalidDiscID;
}

int Driver::usedBlocksCount() const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    return wbfs_count_usedblocks( mHandle.ptr() );
}

int Driver::discImageInfo( const QString& fileName, QWBFS::Model::Disc& disc, partition_selector_t partitionSelection ) const
{
    if ( isWBFSPartitionOrFile( fileName ) ) {
        return wbfsFileInfo( fileName, disc );
    }

    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    void* fileHandle = wbfs_open_file_for_read( fileName.toLocal8Bit().data() );

    if ( !fileHandle ) {
        return Driver::InvalidDisc;
    }

    u8* header = (u8*)wbfs_ioalloc( 0x100 );

    disc.size = wbfs_estimate_disc( mHandle.ptr(), wbfs_read_wii_file, fileHandle, partitionSelection, header );
    disc.origin = fileName;
    discInfo( header, disc );

    wbfs_iofree( header );
    wbfs_close_file( fileHandle );

    return disc.size != 0 ? Driver::Ok : Driver::InvalidDisc;
}

int Driver::addDiscImage( const QString& fileName, progress_callback_t progressCallback, partition_selector_t partitionSelection, bool copy1to1, const QString& newName ) const
{
    mCurrentDriver = const_cast<Driver*>( this );
#ifndef Q_OS_WIN
    Q_UNUSED( newName );
#endif

    if ( !QFile::exists( fileName ) ) {
        return Driver::DiscNotFound;
    }

    QWBFS::Model::Disc disc;
    const int result1 = discImageInfo( fileName, disc );

    if ( result1 != Driver::Ok ) {
        return result1;
    }

    if ( hasDisc( disc.id ) == Driver::DiscFound ) {
        return Driver::DiscFound;
    }

    void* fileHandle = wbfs_open_file_for_read( fileName.toLocal8Bit().data() );

    if ( !fileHandle ) {
        return Driver::DiscReadFailed;
    }

    const u32 result2 = wbfs_add_disc( mHandle.ptr(), wbfs_read_wii_file, fileHandle, progressCallback, partitionSelection, copy1to1 ? 1 : 0
#ifdef Q_OS_WIN
        , newName.isEmpty() ? 0 : newName.toLocal8Bit().data()
#endif
    );

    wbfs_close_file( fileHandle );
    return result2 == 0 ? Driver::Ok : Driver::DiscAddFailed;
}

int Driver::removeDisc( const QString& discId ) const
{
    if ( isOpen() ) {
        if ( wbfs_rm_disc( mHandle.ptr(), (u8*)discId.toLocal8Bit().data() ) == 0 ) {
            return Driver::Ok;
        }

        return Driver::DiscNotFound;
    }

    return Driver::PartitionNotOpened;
}

int Driver::extractDisc( const QString& discId, const QString& path, const QString& _name, progress_callback_t progressCallback ) const
{
    mCurrentDriver = const_cast<Driver*>( this );

    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    // get disc handle
    const QWBFS::Partition::DiscHandle discHandle( mHandle, discId );

    if ( !discHandle.isValid() ) {
        return Driver::DiscNotFound;
    }

    const QString name = _name.isEmpty() ? discHandle.isoName() : _name;
    const QString filePath = QDir::toNativeSeparators( QString( "%1/%2" ).arg( path ).arg( name ) );
    int result = Driver::allocateFile( filePath, ( discHandle.ptr()->p->n_wii_sec_per_disc /2 ) *0x8000ULL );
    void* fileHandle = result == Driver::Ok ? wbfs_open_file_for_write( filePath.toLocal8Bit().data() ) : 0;

    if ( fileHandle ) {
        result = wbfs_extract_disc( discHandle.ptr(), wbfs_write_wii_file, fileHandle, progressCallback );
        wbfs_close_file( fileHandle );
        return result == 0 ? Driver::Ok : Driver::DiscExtractFailed;
    }
    else {
        QFile::remove( filePath );
    }

    return Driver::DiscWriteFailed;
}

int Driver::renameDisc( const QString& discId, const QString& name ) const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    if ( wbfs_ren_disc( mHandle.ptr(), (u8*)discId.toLocal8Bit().data(), (u8*)name.toLocal8Bit().data() ) == 0 ) {
        return Driver::Ok;
    }

    return Driver::DiscNotFound;
}

int Driver::status( QWBFS::Partition::Status& status ) const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    status = QWBFS::Partition::Status( mHandle );
    return Driver::Ok;
}

int Driver::addDisc( const QString& discId, const QWBFS::Partition::Handle& sourcePartitionHandle, progress_callback_t progressCallback, partition_selector_t partitionSelection ) const
{
    mCurrentDriver = const_cast<Driver*>( this );

    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    if ( !sourcePartitionHandle.isValid() ) {
        return Driver::SourcePartitionNotOpened;
    }

    const QWBFS::Partition::DiscHandle discHandle( sourcePartitionHandle, discId );

    if ( !discHandle.isValid() ) {
        return Driver::DiscNotFound;
    }

    if ( hasDisc( discId ) == Driver::DiscFound ) {
        return Driver::DiscFound;
    }

    if ( wbfs_add_disc( mHandle.ptr(), discRead_callback/*wbfs_disc_read*/, discHandle.ptr(), progressCallback, partitionSelection, 0
#ifdef Q_OS_WIN
        , 0
#endif
        ) == 0 ) {
        return Driver::Ok;
    }

    return Driver::DiscAddFailed;
}

int Driver::canDrive2Drive( const QWBFS::Partition::Handle& sourcePartitionHandle ) const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    if ( !sourcePartitionHandle.isValid() ) {
        return Driver::SourcePartitionNotOpened;
    }

    const double left = sourcePartitionHandle.ptr()->wbfs_sec_sz /sourcePartitionHandle.ptr()->hd_sec_sz;
    const double right = mHandle.ptr()->wbfs_sec_sz /mHandle.ptr()->hd_sec_sz;

    if ( qFuzzyCompare( left, right ) ) {
        return Driver::Ok;
    }

    return Driver::CantDrive2Drive;
}

int Driver::hasDisc( const QString& discId ) const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    const QWBFS::Partition::DiscHandle discHandle( mHandle, discId );

    if ( discHandle.isValid() ) {
        return Driver::DiscFound;
    }

    return Driver::DiscNotFound;
}

int Driver::discList( QWBFS::Model::DiscList& list ) const
{
    const int count = discCount();

    if ( count < 0 ) {
        return count; // error
    }

    for ( int index = 0; index < count; index++ ) {
        QWBFS::Model::Disc disc;
        const int result = discInfo( index, disc );

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

        list << disc;
    }

    return Driver::Ok;
}

int Driver::trim() const
{
    if ( !isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    wbfs_trim( mHandle.ptr() );
    wbfs_file_truncate( mHandle.ptr()->callback_data, mHandle.ptr()->n_hd_sec *512ULL );

    return Driver::Ok;
}

bool Driver::isWBFSPartitionOrFile( const QString& _fileName )
{
    QString filePath = _fileName;

#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;
}

int Driver::allocateFile( const QString& filePath, qint64 size )
{
    const int go = 1024 *1024 *1024;
    QFile file( filePath );

    if ( file.exists() ) {
        return Driver::DiscFound;
    }

    if ( file.open( QIODevice::WriteOnly ) ) {
        if ( size == -1 ) {
            if ( file.resize( go *8.8 ) ) { // 8.8 go - all FS except FAT32 // 143432 *2 *0x8000ULL
                return Driver::Ok;
            }
            else if ( file.resize( ( go *4.0 ) -1 ) ) { // 4go - fat32 FS
                return Driver::Ok;
            }
        }
        else if ( file.resize( size ) ) {
            return Driver::Ok;
        }
    }

    file.remove();

    return Driver::DiscWriteFailed;
}

int Driver::wbfsFileInfo( const QString& wbfsFileName, QWBFS::Model::Disc& disc )
{
    /*if ( !isWBFSPartitionOrFile( wbfsFileName ) ) {
        return Driver::InvalidDisc;
    }*/

    wbfs_t* partition = wbfs_try_open_partition( wbfsFileName.toLocal8Bit().data(), 0 );

    if ( !partition ) {
        return Driver::InvalidDisc;
    }

    u8* header = (u8*)wbfs_ioalloc( 0x100 );
    int count = wbfs_count_discs( partition );

    if ( count != 1 ) {
        wbfs_iofree( header );
        wbfs_close( partition );
        return Driver::InvalidDisc;
    }

    wbfs_disc_t* cd;
    quint32 size;

    if( !wbfs_get_disc_info( partition, 0, header, 0x100, &size ) ) {
        cd = wbfs_open_disc( partition, header );

        if ( !cd ) {
            wbfs_iofree( header );
            wbfs_close( partition );
            return Driver::InvalidDisc;
        }

        wbfs_close_disc( cd );
    }

    disc.size = size *4ULL;
    disc.origin = wbfsFileName;
    discInfo( header, disc );

    wbfs_iofree( header );
    wbfs_close( partition );

    return disc.size != 0 ? Driver::Ok : Driver::InvalidDisc;
}

int Driver::convertIsoFileToWBFSFile( const QString& isoFilePath, const QString& _wbfsFilePath )
{
    int result;
    QString wbfsFilePath = _wbfsFilePath;

    if ( wbfsFilePath.isEmpty() ) {
        wbfsFilePath = QString( "%1.wbfs" ).arg( isoFilePath );
    }

    result = Driver::allocateFile( wbfsFilePath );

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

    QWBFS::Partition::Properties properties( wbfsFilePath );
    properties.reset = true;

    QWBFS::Partition::Handle handle( properties );
    QWBFS::Driver td( 0, handle );

    if ( !td.isOpen() ) {
        return Driver::PartitionNotOpened;
    }

    QWBFS::Model::Disc disc;
    result = td.discImageInfo( isoFilePath, disc );

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

    result = td.addDiscImage( disc.origin );

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

    return td.trim();
}

QString Driver::errorToString( QWBFS::Driver::Error error )
{
    switch ( error ) {
        case Driver::Ok:
            return tr( "No error" );
        case Driver::PartitionNotOpened:
            return tr( "Partition not opened" );
        case Driver::SourcePartitionNotOpened:
            return tr( "Source partition not opened" );
        case Driver::DiscReadFailed:
            return tr( "Disc read failed" );
        case Driver::DiscWriteFailed:
            return tr( "Disc write failed" );
        case Driver::DiscExtractFailed:
            return tr( "Disc extract failed" );
        case Driver::DiscAddFailed:
            return tr( "Disc add failed" );
        case Driver::DiscConvertFailed:
            return tr( "Disc convert failed" );
        case Driver::DiscRenameFailed:
            return tr( "Disc rename failed" );
        case Driver::DiscFound:
            return tr( "Disc found" );
        case Driver::DiscNotFound:
            return tr( "Disc not found (or not exists)" );
        case Driver::InvalidDiscIndex:
            return tr( "Invalid disc index" );
        case Driver::InvalidDiscID:
            return tr( "Invalid disc id" );
        case Driver::InvalidDisc:
            return tr( "Invalid disc" );
        case Driver::CantDrive2Drive:
            return tr( "Can't drive to drive copy" );
        case Driver::UnknownError:
            return tr( "Unknown error" );
    }

    return QString::null;
}

QString Driver::regionToString( int region )
{
    return mRegions.value( region, "Unknow Region" );
}

QString Driver::regionToLanguageString( int region )
{
    const QString systemLanguage = QLocale::system().name().section( '_', 0, 0 ).toUpper();
    return mLanguages.value( region, systemLanguage.isEmpty() ? "EN" : systemLanguage );
}

QString Driver::stateToString( QWBFS::Driver::State state )
{
    switch ( state ) {
        case Driver::None:
            return tr( "None" );
        case Driver::Success:
            return tr( "Success" );
        case Driver::Failed:
            return tr( "Failed" );
    }

    return QString::null;
}

void Driver::setForceMode( bool force )
{
    QMutexLocker locker( &mMutex );
    mForce = force;
    wbfs_set_force_mode( mForce ? 1 : 0 );
}

bool Driver::forceMode()
{
    QMutexLocker locker( &mMutex );
    return mForce;
}

void Driver::addHandle( const QWBFS::Partition::Handle& handle )
{
    if ( !handle.isValid() ) {
        return;
    }

    QMutexLocker locker( &mMutex );
    mHandles[ handle.partition() ] = handle;
}

QWBFS::Partition::Handle Driver::getHandle( const QString& partition, bool* created )
{
    QMutexLocker locker( &mMutex );
    QWBFS::Partition::Handle handle = mHandles.value( partition );

    if ( created ) {
        *created = false;
    }

    if ( !handle.isValid() ) {
        const QWBFS::Partition::Handle _handle( partition );

        if ( _handle.isValid() ) {
            mHandles[ partition ] = _handle;
            handle = _handle;

            if ( created ) {
                *created = true;
            }
        }
    }

    return handle;
}

void Driver::closeHandle( const QWBFS::Partition::Handle& handle )
{
    QMutexLocker locker( &mMutex );
    mHandles.remove( handle.partition() );
}

int Driver::u8StrLength( u8* str )
{
    int counter = 0;
    int length = 0;

    while ( str[ counter++ ] != '\0' ) {
        length++;
    }

    return length;
}

void Driver::discInfo( u8* header, QWBFS::Model::Disc& disc )
{
    const int offset = 0x20;
    const int length = u8StrLength( header +offset );

    disc.id = QString::fromLocal8Bit( (const char*)header, 6 );
    disc.title = QString::fromLocal8Bit( (const char*)header +offset, length );
    disc.region = QChar( header[ 0x3 ] ).unicode();
}

qint64 Driver::minimumWBFSFileSize()
{
    return WBFS_FILE_MINIMUM_SIZE;
}

QWBFS::Model::Disc Driver::isoDiscInfo( const QString& filePath )
{
    const QString tmpFile = QString( "%1/%2.tmp%3" )
        .arg( QDir::tempPath() )
        .arg( QApplication::applicationName() )
        .arg( minimumWBFSFileSize() );
    QWBFS::Model::Disc disc;

    // create temporary wbfs container for estimating the size
    if ( !QFile::exists( tmpFile ) ) {
        if ( Driver::allocateFile( tmpFile, minimumWBFSFileSize() ) != QWBFS::Driver::Ok ) {
            qWarning() << Q_FUNC_INFO << "Can't create tmp file" << tmpFile.toLocal8Bit().constData();
            return disc;
        }
    }

    QWBFS::Partition::Properties properties( tmpFile );
    properties.reset = true;

    QWBFS::Partition::Handle handle( properties );

    if ( handle.isValid() ) {
        void* fileHandle = wbfs_open_file_for_read( filePath.toLocal8Bit().data() );

        if ( fileHandle ) {
            u8* header = (u8*)wbfs_ioalloc( 0x100 );

            disc.size = wbfs_estimate_disc( handle.ptr(), wbfs_read_wii_file, fileHandle, ONLY_GAME_PARTITION, header );
            disc.origin = filePath;
            discInfo( header, disc );

            wbfs_iofree( header );
            wbfs_close_file( fileHandle );
        }
        else {
            qWarning() << Q_FUNC_INFO << "Invalid file handle";
        }
    }
    else {
        qWarning() << Q_FUNC_INFO << "Invalid wbfs handle";
    }

    //QFile::remove( tmpFile ); // should delete it but may be not performant for multiple requests of iso estimated size

    return disc;
}

Driver::FileType Driver::fileType( const QString& filePath )
{
    const QFileInfo file( filePath );
    const QString suffix = file.isDir() ? QString::null : file.suffix().toLower();

    if ( suffix == "iso" ) {
        return QWBFS::Driver::ISOFile;
    }
    else if ( suffix == "wbfs" ) {
        if ( isWBFSPartitionOrFile( filePath ) ) {
            return QWBFS::Driver::WBFSFile;
        }
    }
    else if ( suffix.isEmpty() ) {
        if ( isWBFSPartitionOrFile( filePath ) ) {
            return QWBFS::Driver::WBFSPartitionFile;
        }
    }

    return QWBFS::Driver::UnknownFile;
}

int Driver::discRead_callback( void* fp, u32 lba, u32 count, void* iobuf )
{
    int ret = wbfs_disc_read( (wbfs_disc_t*)fp, lba, (u8*)iobuf, count );
    static int num_fail = 0;

    if ( ret ) {
        if ( num_fail == 0 ) {
            qWarning() << "Error reading lba probably the two wbfs don't have the same granularity. Ignoring...";
        }

        if ( num_fail++ > 0x100 ) {
            qWarning() << "Too many error giving up...";
            return 1;
        }
    }
    else {
        num_fail = 0;
    }

    return 0;
}

QTime Driver::estimatedTimeForTask( int x, int max )
{
    static time_t start_time;
    static u32 expected_total;
    u32 d;
    u32 h, m, s;

    if ( x == 0 ) {
        start_time = time( 0 );
        expected_total = 300;
    }

    if ( x == max ) {
        d = (u32)( time( 0 ) -start_time );
        h = d /3600;
        m = ( d /60 ) %60;
        s = d %60;

        return QTime( h, m, s );
    }

    d = (u32)( time( 0 ) -start_time );

    if ( x != 0 ) {
        expected_total = (u32)( ( 3 *expected_total +d *max /x ) /4 );
    }

    if ( expected_total > d ) {
        d = expected_total -d;
    }
    else {
        d = 0;
    }

    h = d /3600;
    m = ( d /60 ) %60;
    s = d %60;

    return QTime( h, m, s );
}

void Driver::progress_callback( int x, int max )
{
    if ( mCurrentDriver ) {
        emit mCurrentDriver->currentProgressChanged( x, max, estimatedTimeForTask( x, max ) );
    }
}


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  : Driver.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 DRIVER_H
#define DRIVER_H

#include <QObject>
#include <QStringList>
#include <QTime>
#include <QMutex>

#include "qwbfsdriver/PartitionProperties.h"
#include "qwbfsdriver/PartitionHandle.h"
#include "qwbfsdriver/PartitionStatus.h"

namespace QWBFS {
namespace Model {
struct Disc;
typedef QList<struct Disc> DiscList;
}; // Model

class Driver : public QObject
{
    Q_OBJECT

public:
    enum State {
        None = 0,
        Success,
        Failed
    };

    enum Error {
        Ok = 0,
        PartitionNotOpened = -1,
        SourcePartitionNotOpened = -2,
        DiscReadFailed = -3,
        DiscWriteFailed = -4,
        DiscExtractFailed = -5,
        DiscAddFailed = -6,
        DiscConvertFailed = -7,
        DiscRenameFailed = -8,
        DiscFound = -9,
        DiscNotFound = -10,
        InvalidDiscIndex = -11,
        InvalidDiscID = -12,
        InvalidDisc = -13,
        CantDrive2Drive = -14,
        UnknownError = -1000
    };

    enum FileType {
        UnknownFile = 0,
        WBFSPartitionFile,
        WBFSFile,
        ISOFile
    };

    Driver( QObject* parent = 0, const QWBFS::Partition::Handle& partitionHandle = QWBFS::Partition::Handle() );
    Driver( const QWBFS::Partition::Handle& partitionHandle );
    virtual ~Driver();

    void setPartition( const QString& partition );
    QString partition() const;

    QWBFS::Partition::Handle handle() const;

    /*!
        \details open the partition.
        \param none.
        \return return true on success, else false.
    */
    bool open();
    /*!
        \details close the partition.
        \param none.
        \return none.
    */
    void close();
    /*!
        \details return the partition open state.
        \param none.
        \return return true if open, else false.
    */
    bool isOpen() const;
    /*!
        \details format the partition, closing it first if needed. /!\ Be sure to close all opened handle of the same partition first.
        \param none.
        \return return true on success, else false.
    */
    bool format();
    /*!
        \details return the disc count.
        \param none.
        \return PartitionNotOpened or the disc count.
    */
    int discCount() const;
    /*!
        \details return a filled disc structure.
        \param index the disc index position in the wbfs partition.
        \param discId the disc ID of the disc.
        \param disc the structure to be filled.
        \return PartitionNotOpened, InvalidDiscIndex, InvalidDiscID or Ok.
    */
    int discInfo( int index, QWBFS::Model::Disc& disc ) const;
    int discInfo( const QString& discId, QWBFS::Model::Disc& disc ) const;
    /*!
        \details return the used blocks count.
        \param none.
        \return PartitionNotOpened or the used blocks count.
    */
    int usedBlocksCount() const;
    /*!
        \details return a filled disc structure.
        \param fileName the file to get informations from.
        \param partitionSelector the partition selector.
        \param disc the disc to fill informations.
        \return PartitionNotOpened or the used blocks count.
    */
    int discImageInfo( const QString& fileName, QWBFS::Model::Disc& disc, partition_selector_t partitionSelection = ONLY_GAME_PARTITION ) const;
    /*!
        \details add a disc image in the partition.
        \param fileName the disc image file path to add.
        \param progressCallback the progress callback to use.
        \param partitionSelection the partition to add.
        \param copy1to1 do a 1to1 copy or not.
        \param newName a new name to use for the added disc. /!\ windows only.
        \return PartitionNotOpened, DiscReadFailed, DiscAlreadyInPartition, DiscAddFailed or Ok
    */
    int addDiscImage( const QString& fileName, progress_callback_t progressCallback = Driver::progress_callback, partition_selector_t partitionSelection = ONLY_GAME_PARTITION, bool copy1to1 = false, const QString& newName = QString::null ) const;
    /*!
        \details remove a disc from the partition.
        \param discId the disc id to remove.
        \return remove a disc from the partition.
    */
    int removeDisc( const QString& discId ) const;
    /*!
        \details extract a disc from the wbfs partition to a path.
        \param discId the disc id to extract.
        \param path the path where to extract the disc.
        \param progressCallback the progress callback to use.
        \param name the name of the iso if not null, else the name is based on the disc title.
        \return PartitionNotOpened, DiscNotFound, DiscExtractFailed, DiscWriteFailed or Ok.
    */
    int extractDisc( const QString& discId, const QString& path, const QString& name = QString::null, progress_callback_t progressCallback = Driver::progress_callback ) const;
    /*!
        \details rename the disc id to another name.
        \param discId the disc id to rename.
        \param name the new name to set for the disc.
        \return PartitionNotOpened, DiscNotFound, or Ok.
    */
    int renameDisc( const QString& discId, const QString& name ) const;
    /*!
        \details fill a status structure with partition infos.
        \param status the structure to be filled with partition status.
        \return PartitionNotOpened or Ok.
    */
    int status( QWBFS::Partition::Status& status ) const;
    /*!
        \details add a disc from another partition aka drive2drive copy.
        \param discId the disc id to copy.
        \param sourcePartitionHandle the partition to read disc from.
        \return PartitionNotOpened, SourcePartitionNotOpened, DiscNotFound, DiscAlreadyInPartition, DiscAddFailed or Ok.
    */
    int addDisc( const QString& discId, const QWBFS::Partition::Handle& sourcePartitionHandle, progress_callback_t progressCallback = Driver::progress_callback, partition_selector_t partitionSelection = ONLY_GAME_PARTITION ) const;
    /*!
        \details check if drive2drive copy is possible.
        \param handle the source partition handle.
        \return PartitionNotOpened, SourcePartitionNotOpened, CantDrive2Drive or Ok
    */
    int canDrive2Drive( const QWBFS::Partition::Handle& sourcePartitionHandle ) const;
    /*!
        \details check if a disc is in the partition.
        \param discId the disc id to check.
        \return PartitionNotOpened, DiscNotFound or DiscFound
    */
    int hasDisc( const QString& discId ) const;
    /*!
        \details list all dics in the partition
        \param list the list to fill of discs
        \return Ok or wbfs error code
    */
    int discList( QWBFS::Model::DiscList& list ) const;
    /*!
        \details truncate the file system to its minimum size (for creating stand alone wbfs files)
        \return PartitionNotOpened or Ok
    */
    int trim() const;
    /*!
        \details return if a file is a wbfs partition/file.
        \param fileName the fileName to check.
        \return return true if fileName is a wbfs partition/file, else false.
    */
    static bool isWBFSPartitionOrFile( const QString& fileName );
    /*!
        \details initialize a file having \a size bytes
        \param filePath the filepath where to initialize the file
        \param size the size to allocate in the file
        \return DiscWriteFailed or Ok
    */
    static int allocateFile( const QString& filePath, qint64 size = -1 );
    /*!
        \details return a filled disc structure.
        \param wbfsFileName the wbfs file to get informations from.
        \param partitionSelector the partition selector.
        \param disc the disc to fill informations.
        \return InvalidDisc or Ok
    */
    static int wbfsFileInfo( const QString& wbfsFileName, QWBFS::Model::Disc& disc );
    /*!
        \details convert an iso file to a wbfs file
        \param isoFilePath the source iso file path
        \param wbfsFilePath the target wbfs file path if setted, else isoFilePath +".wbfs"
        \return DiscReadFailed, addDiscImage result or Ok
    */
    static int convertIsoFileToWBFSFile( const QString& isoFilePath, const QString& wbfsFilePath = QString::null );
    /*!
        \details return a string representation of the error.
        \param error the error to represent.
        \return return a QString representing the textual error message.
    */
    static QString errorToString( QWBFS::Driver::Error error );
    /*!
        \details return a string representation of the region.
        \param region the region to represent.
        \return return a QString representing the textual region.
    */
    static QString regionToString( int region );
    /*!
        \details return a string representation of the region language.
        \param region the region language to represent.
        \return return a QString representing the textual region language.
    */
    static QString regionToLanguageString( int region );
    /*!
        \details return a string representation of the state.
        \param state the state to represent.
        \return return a QString representing the textual state.
    */
    static QString stateToString( QWBFS::Driver::State state );
    /*!
        \details set the force mode of the libwbfs.
        \param force true to force, else false.
        \return none.
    */
    static void setForceMode( bool force );
    /*!
        \details return the force mode of the libwbfs.
        \param none.
        \return return true if force is active, else false.
    */
    static bool forceMode();

    static void addHandle( const QWBFS::Partition::Handle& handle );
    static QWBFS::Partition::Handle getHandle( const QString& partition, bool* created = 0 );
    static void closeHandle( const QWBFS::Partition::Handle& handle );

    static void discInfo( u8* header, QWBFS::Model::Disc& disc );
    static qint64 minimumWBFSFileSize();
    static QWBFS::Model::Disc isoDiscInfo( const QString& filePath );
    static Driver::FileType fileType( const QString& filePath );

    static QTime estimatedTimeForTask( int value, int maximum );

protected:
    mutable QWBFS::Partition::Properties mProperties;
    QWBFS::Partition::Handle mHandle;
    bool mHasCreatedHandle;

    static QMutex mMutex;
    static bool mForce;
    static QWBFS::Driver* mCurrentDriver;
    static QHash<QString, QWBFS::Partition::Handle> mHandles;
    static QHash<int, QString> mLanguages;
    static QHash<int, QString> mRegions;

    void init();

    static int u8StrLength( u8* str );

    static int discRead_callback( void* fp, u32 lba, u32 count, void* iobuf );
    static void progress_callback( int value, int maximum );

signals:
    void currentProgressChanged( int value, int maximum, const QTime& remaining );
    void globalProgressChanged( int value, int maximum );
};

}; // QWBFS

#endif // DRIVER_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   : QWBFS Manager
** FileName  : PartitionDiscHandle.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 "PartitionDiscHandle.h"

#include <QDebug>

using namespace QWBFS::Partition;
using namespace QWBFS::Partition::Internal;

// DiscHandleData

DiscHandleData::DiscHandleData( const QWBFS::Partition::Handle& _handle, const QString& _discId )
{
    handle = wbfs_open_disc( _handle.ptr(), (u8*)( _discId.toLocal8Bit().data() ) );
    discId = _discId;
    index = handle ? handle->i : -1;

    if ( handle ) {
        QString( "*** Opened disc: %1" ).arg( discId ).toLocal8Bit().constData();
    }
}

DiscHandleData::DiscHandleData( const DiscHandleData& other )
    : QSharedData( other )
{
    handle = other.handle;
    discId = other.discId;
    index = other.index;
}

DiscHandleData::~DiscHandleData()
{
    if ( handle ) {
        wbfs_close_disc( handle );
        QString( "*** Closed disc: %1" ).arg( discId ).toLocal8Bit().constData();
    }

    //qWarning() << Q_FUNC_INFO;
}

// DiscHandleData

DiscHandle::DiscHandle( const QWBFS::Partition::Handle& handle, const QString& discId )
{
    d = new DiscHandleData( handle, discId );
}

DiscHandle::~DiscHandle()
{
    //qWarning() << Q_FUNC_INFO;
}

QString DiscHandle::discId() const
{
    return d->discId;
}

int DiscHandle::index() const
{
    return d->index;
}

QString DiscHandle::isoName() const
{
    if ( !isValid() ) {
        return QString::null;
    }

    QString isoName = QString::fromLocal8Bit( QString::fromLocal8Bit( (char*)d->handle->header->disc_header_copy +0x20, 0x100 )
        .replace( ' ', '_' )
        .replace( '/', '_' )
        .replace( ':', '_' ).trimmed().toLocal8Bit().constData() );

    while ( isoName.contains( "__" ) ) {
        isoName.replace( "__", "_" );
    }

    if ( isoName.length() >= 0x100 ) {
        isoName.chop( ( isoName.length() -0x100 ) +4 );
    }

    isoName.append( ".iso" );

    return isoName;
}

bool DiscHandle::isValid() const
{
    return d->handle;
}

wbfs_disc_t* DiscHandle::ptr() const
{
    return d->handle;
}


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  : PartitionDiscHandle.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 PARTITIONDISCHANDLE_H
#define PARTITIONDISCHANDLE_H

#include <QSharedData>

#include "qwbfsdriver/PartitionHandle.h"

namespace QWBFS {
namespace Partition {

namespace Internal {

class DiscHandleData : public QSharedData
{
public:
    DiscHandleData( const QWBFS::Partition::Handle& handle = QWBFS::Partition::Handle(), const QString& discId = QString::null );
    DiscHandleData( const DiscHandleData& other );
    ~DiscHandleData();

    wbfs_disc_t* handle;
    QString discId;
    int index;
};

}; // Internal

struct DiscHandle
{
    DiscHandle( const QWBFS::Partition::Handle& handle, const QString& discId );
    ~DiscHandle();

    bool isValid() const;
    wbfs_disc_t* ptr() const;

    QString discId() const;
    int index() const;
    QString isoName() const;

protected:
    QSharedDataPointer<Internal::DiscHandleData> d;
};

}; // Partition
}; // QWBFS

#endif // PARTITIONDISCHANDLE_H