#include "batch.h"
#include "uimanager.h"
#include "browser.h"
#include "dialogs.h"
#include "imageutils.h"
#include "ifapp.h"
#include "jpegtransform.h"
#include <qlabel.h>
#include <qbuttongroup.h>
#include <qpushbutton.h>
#include <qradiobutton.h>
#include <qgroupbox.h>
#include <qinputdialog.h>
#include <qlayout.h>
#include <qfontmetrics.h>
#include <qfileinfo.h>
#include <qpainter.h>
#include <qbuffer.h>
#include <klocale.h>
#include <kprogress.h>
#include <kapp.h>
#include <kglobal.h>
#include <kconfig.h>
#include <kbuttonbox.h>
#include <kmessagebox.h>
#include <kcolordialog.h>
#include <kimageeffect.h>
#include <kseparator.h>

void createTextLabel(const QString &text, const QColor &color,
                     const QFont &font, QImage &destImage)
{
    QFontMetrics fm(font);
    QRect r(0, 0, fm.width(text), fm.height());

    // TODO: Get rid of tmp pixmap and Qt - call FreeType or Magick's annotate
    // directly
    QPixmap tmpPix(r.width(), r.height());
    tmpPix.fill(Qt::black);
    QPainter p;
    p.begin(&tmpPix);
    p.setFont(font);
    p.setPen(Qt::white);
    p.drawText(0, 0, r.width(), r.height(), Qt::AlignCenter, text);
    p.end();

    destImage.reset();
    destImage.create(r.width(), r.height(), 32);
    QImage srcImage = tmpPix.convertToImage();
    if(srcImage.depth() < 32)
        srcImage.convertDepth(32);

    unsigned int *dest = (unsigned int *)destImage.bits();
    unsigned int *src = (unsigned int *)srcImage.bits();
    int i, len = r.width()*r.height();

    for(i=0; i < len; ++i){
        if(src[i] == Qt::black.rgb())
            dest[i] = qRgba(0, 0, 0, 0);
        else if(src[i] == Qt::white.rgb())
            dest[i] = color.rgb();
        else{
            // src will be grayscale, so just use red for alpha
            dest[i] = qRgba(color.red(), color.green(), color.blue(),
                            qRed(src[i]));
        }
    }
}

bool applyTextLabel(TextPosition pos, QImage &textImage, QImage &destImage)
{
    if(textImage.width() > destImage.width() ||
       textImage.height() > destImage.height()){
        // TODO: error dlg
        qWarning("Image too small for text label! Skipping.");
        return(false);
    }
    int sx, sy, dx, dy;
    int xstart, ystart;
    unsigned int *src, *dest;
    int r, g, b, alpha;

    if(pos == UpperLeftText){
        xstart = 0;
        ystart = 0;
    }
    else if(pos == BottomLeftText){
        xstart = 0;
        ystart = destImage.height()-textImage.height()-1;
    }
    else if(pos == UpperRightText){
        xstart = destImage.width()-textImage.width()-1;
        ystart = 0;
    }
    else if(pos == BottomRightText){
        xstart = destImage.width()-textImage.width()-1;
        ystart = destImage.height()-textImage.height()-1;
    }
    else{ // center
        xstart = ((destImage.width()-textImage.width())/2)-1;
        ystart = ((destImage.height()-textImage.height())/2)-1;
    }

    for(sy = 0, dy = ystart; sy < textImage.height(); ++sy, ++dy){
        src = (unsigned int *)textImage.scanLine(sy);
        dest = (unsigned int *)destImage.scanLine(dy);
        for(sx = 0, dx = xstart; sx < textImage.width(); ++sx, ++dx){
            alpha = qAlpha(src[sx]);
            if(!alpha)
                ;
            else if(alpha == 255)
                dest[dx] = src[sx];
            else{
                float srcPercent = ((float)alpha)/255.0;
                float destPercent = 1.0-srcPercent;
                r = (int)(qRed(src[sx])*srcPercent + qRed(dest[dx])*destPercent);
                g = (int)(qGreen(src[sx])*srcPercent + qGreen(dest[dx])*destPercent);
                b = (int)(qBlue(src[sx])*srcPercent + qBlue(dest[dx])*destPercent);
                dest[dx] = qRgba(r, g, b, 255);
            }
        }
    }
    return(true);
}

bool getRadiusAndDeviation(const QString &caption, double &radius,
                           double &stdDeviation, QWidget *parent)
{
    KIFGet2DoubleDialog dlg(caption,
                            i18n("Radius (use 0 for default)"),
                            5.0, -5.0, 0.1, 0.0,
                            i18n("Standard deviation:"),
                            5.0, -5.0, 0.1, 1.0, parent);
    dlg.setCaption(i18n("Effect Parameters"));
    if(dlg.exec() == QDialog::Accepted){
        radius = dlg.value1();
        stdDeviation = dlg.value2();
        return(true);
    }
    return(false);
}

KIFBatchPixmapView::KIFBatchPixmapView(QWidget *parent, const char *name)
    : QScrollView(parent, name)
{
    pix = NULL;
}

KIFBatchPixmapView::~KIFBatchPixmapView()
{
    qWarning("In batch pixmap view destructor");
    if(pix)
        delete pix;
}

void KIFBatchPixmapView::setImage(QImage &img)
{
    if(!pix)
        pix = new QPixmap(img.width(), img.height());
    convertImageToPixmap(img, *pix);
    resizeContents(img.width(), img.height());
    repaintContents();
}

void KIFBatchPixmapView::drawContents(QPainter *p, int x, int y,
                                      int w, int h)
{
    if(!pix)
        return;
    else
        p->drawPixmap(x, y, *pix, x, y, w, h);
}

KIFSineWaveDialog::KIFSineWaveDialog(QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    setCaption(i18n("Sine Wave Parameters"));
    QVBoxLayout *layout = new QVBoxLayout(this, 10);
    QLabel *lbl = new QLabel(i18n("Please enter the amplitude and\n\
frequency of the sine wave."), this);
    layout->addWidget(lbl);

    aInput = new KDoubleNumInput(25.0, this);
    aInput->setLabel(i18n("Amplitude"), AlignVCenter);
    layout->addWidget(aInput);
    fInput = new KDoubleNumInput(150.0, this);
    fInput->setLabel(i18n("Frequency"), AlignVCenter);
    layout->addWidget(fInput);

    layout->addStretch();

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(accept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addWidget(bbox);
};

KIFShadeDialog::KIFShadeDialog(QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    setCaption(i18n("Shade Parameters"));
    QVBoxLayout *layout = new QVBoxLayout(this, 10);
    QLabel *lbl = new QLabel(i18n("Please enter the direction of the shading"),
                             this);
    layout->addWidget(lbl);

    aInput = new KDoubleNumInput(30.0, this);
    aInput->setLabel(i18n("Azimuth"), AlignVCenter);
    layout->addWidget(aInput);
    eInput = new KDoubleNumInput(30.0, this);
    eInput->setLabel(i18n("Elevation"), AlignVCenter);
    layout->addWidget(eInput);
    KSeparator *sep = new KSeparator(Qt::Horizontal, this);
    layout->addWidget(sep);
    colorCB = new QCheckBox(i18n("Color shading"), this);
    colorCB->setChecked(true);
    layout->addWidget(colorCB);

    layout->addStretch();

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(accept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addWidget(bbox);
};

KIFTextDialog::KIFTextDialog(QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    KConfig *config = KGlobal::config();
    QString oldGrp = config->group();
    config->setGroup("BatchAddText");

    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    QGroupBox *alignGroup= new QGroupBox(i18n("Text Position"), this);
    alignBtns = new QButtonGroup(this);
    alignBtns->hide();
    QGridLayout *alignLayout = new QGridLayout(alignGroup, 1, 1, 15);

    QRadioButton *ulBtn = new QRadioButton(i18n("Upper Left"), alignGroup);
    alignBtns->insert(ulBtn, UpperLeftText);
    alignLayout->addWidget(ulBtn, 0, 0);
    QRadioButton *urBtn = new QRadioButton(i18n("Upper Right"), alignGroup);
    alignBtns->insert(urBtn, UpperRightText);
    alignLayout->addWidget(urBtn, 0, 2);
    QRadioButton *cBtn = new QRadioButton(i18n("Centered"), alignGroup);
    alignBtns->insert(cBtn, CenterText);
    alignLayout->addWidget(cBtn, 1, 1);
    QRadioButton *llBtn = new QRadioButton(i18n("Lower Left"), alignGroup);
    alignBtns->insert(llBtn, BottomLeftText);
    alignLayout->addWidget(llBtn, 2, 0);
    QRadioButton *lrBtn = new QRadioButton(i18n("Lower Right"), alignGroup);
    alignBtns->insert(lrBtn, BottomRightText);
    alignLayout->addWidget(lrBtn, 2, 2);
    mainLayout->addWidget(alignGroup);
    alignBtns->setButton(0);

    QGroupBox *colorGroup = new QGroupBox(i18n("Text Options"), this);
    QHBoxLayout *colorLayout = new QHBoxLayout(colorGroup, 15);
    QLabel *colorLbl = new QLabel(i18n("Text color:"), colorGroup);
    colorLayout->addWidget(colorLbl);
    colorBtn = new KColorButton(colorGroup);
    colorBtn->setColor(config->readColorEntry("Color", &Qt::black));
    colorLayout->addWidget(colorBtn);
    numInput = new KIntNumInput(100, colorGroup);
    numInput->setLabel(i18n("Opacity"), AlignLeft);
    numInput->setRange(10, 100);
    numInput->setValue(config->readNumEntry("Opacity", 100));
    colorLayout->addWidget(numInput);

    mainLayout->addWidget(colorGroup);

    fontChooser = new KFontChooser(this);
    fontChooser->setSampleText(config->readEntry("Text", i18n("Add your text here!")));
    mainLayout->addWidget(fontChooser);

    mainLayout->addStretch();

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);

    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(accept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    mainLayout->addWidget(bbox);

    setCaption(i18n("Add Text Options"));
    config->setGroup(oldGrp);
}

void KIFTextDialog::accept()
{
    qWarning("In KIFTextDialog::accept");
    if(result() == Accepted){
        KConfig *config = KGlobal::config();
        QString oldGrp = config->group();
        config->setGroup("BatchAddText");
        config->writeEntry("Color", colorBtn->color());
        config->writeEntry("Opacity", numInput->value());
        config->writeEntry("Text", fontChooser->sampleText());
        config->sync();
    }
    QDialog::accept();
}

TextPosition KIFTextDialog::pos()
{
    if(alignBtns->selected())
        return((TextPosition)alignBtns->id(alignBtns->selected()));
    return(UpperLeftText);
}

KIFGet2DoubleDialog::KIFGet2DoubleDialog(const QString &captionStr,
                                         const QString &input1Str,
                                         double input1Upper, double input1Lower,
                                         double input1Step, double input1Val,
                                         const QString &input2Str,
                                         double input2Upper, double input2Lower,
                                         double input2Step, double input2Val,
                                         QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    QGridLayout *layout = new QGridLayout(this, 1, 1, 5, 5);
    QLabel *lbl = new QLabel(captionStr, this);
    lbl->setAlignment(Qt::AlignCenter);
    layout->addMultiCellWidget(lbl, 1, 1, 0, 2);
    layout->addRowSpacing(2, 10);

    lbl = new QLabel(input1Str, this);
    lbl->setAlignment(AlignRight | AlignVCenter);
    layout->addWidget(lbl, 3, 1);
    lbl  = new QLabel(input2Str, this);
    lbl->setAlignment(AlignRight | AlignVCenter);
    layout->addWidget(lbl, 4, 1);

    spinBox1 = new KDoubleSpinBox(input1Lower, input1Upper, input1Step,
                                  input1Val, 2, this);
    layout->addWidget(spinBox1, 3, 2);
    spinBox2 = new KDoubleSpinBox(input2Lower, input2Upper, input2Step,
                                  input2Val, 2, this);
    layout->addWidget(spinBox2, 4, 2);

    layout->addRowSpacing(5, 10);
    layout->addMultiCellWidget(new KSeparator(Qt::Horizontal, this), 6, 6, 0, 2);

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(accept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addMultiCellWidget(bbox, 7, 7, 0, 2);
    layout->setRowStretch(5, 1);
    layout->setColStretch(0, 1);
}

KIFBatchProgressWidget::KIFBatchProgressWidget(BatchEffect *effectMgr,
                                               QWidget *parent,
                                               const char *name)
    : QWidget(parent, name)
{
    QVBoxLayout *layout = new QVBoxLayout(this, 5, 5);
    captionLbl = new QLabel(i18n("Filename:"), this);
    layout->addWidget(captionLbl);
    layout->addSpacing(16);
    lbl = new QLabel(i18n("Status..."), this);
    layout->addWidget(lbl);
    progress = new KProgress(100, this);
    layout->addWidget(progress);
    layout->addStretch(1);
    layout->addWidget(new KSeparator(Qt::Horizontal, this));
    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), effectMgr,
            SLOT(slotCancel()));
    bbox->addStretch(1);
    layout->addWidget(bbox);

    setCaption(i18n("Batch Effect Progress"));
    setMinimumWidth(350);
    resize(sizeHint());
    show();
}

void KIFBatchProgressWidget::setTitle(const QString &captionStr)
{
    captionLbl->setText(captionStr);
}

KProgress* KIFBatchProgressWidget::progressBar()
{
    return(progress);
}

QLabel* KIFBatchProgressWidget::progressLabel()
{
    return(lbl);
}

KIFBatchPreviewWidget::KIFBatchPreviewWidget(BatchEffect *effectMgr,
                                             QWidget *parent,
                                             const char *name)
    : QWidget(parent, name)
{
    QGridLayout *layout = new QGridLayout(this, 1, 1, 5, 5);
    preview = new KIFBatchPixmapView(this);
    layout->addMultiCellWidget(preview, 1, 1, 0, 1);

    captionLbl = new QLabel(i18n("Filename:"), this);
    layout->addMultiCellWidget(captionLbl, 2, 2, 0, 1);

    progress = new KProgress(100, this);
    layout->addWidget(progress, 3, 0);
    lbl = new QLabel(i18n("Status..."), this);
    layout->addWidget(lbl, 3, 1);

    layout->addMultiCellWidget(new KSeparator(Qt::Horizontal, this),
                               4, 4, 0, 1);

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
    acceptBtn = bbox->addButton(i18n("Accept this effect"));
    connect(acceptBtn, SIGNAL(clicked()), effectMgr,
            SLOT(slotAcceptPreview()));
    skipBtn = bbox->addButton(i18n("Skip this effect"));
    connect(skipBtn, SIGNAL(clicked()), effectMgr, SLOT(slotRejectPreview()));
    cancelBtn = bbox->addButton(i18n("Cancel all effects"));
    connect(cancelBtn, SIGNAL(clicked()), effectMgr, SLOT(slotCancel()));

    connect(this, SIGNAL(windowClosed()), effectMgr, SLOT(slotCancel()));
    layout->addMultiCellWidget(bbox, 5, 5, 0, 1);
    layout->setColStretch(1, 1);
    layout->setRowStretch(1, 1);
    setCaption(i18n("Batch Effect Preview"));
    setMinimumWidth(450);
    resize(sizeHint());
    show();
}

void KIFBatchPreviewWidget::setTitle(const QString &captionStr)
{
    captionLbl->setText(captionStr);
}

KProgress* KIFBatchPreviewWidget::progressBar()
{
    return(progress);
}

QLabel* KIFBatchPreviewWidget::progressLabel()
{
    return(lbl);
}

void KIFBatchPreviewWidget::setPreviewImage(QImage &img)
{
    preview->setImage(img);
    acceptBtn->setEnabled(true);
    skipBtn->setEnabled(true);
    cancelBtn->setEnabled(true);
}

void KIFBatchPreviewWidget::disable()
{
    acceptBtn->setEnabled(false);
    skipBtn->setEnabled(false);
    cancelBtn->setEnabled(false);
}

void KIFBatchPreviewWidget::closeEvent(QCloseEvent *)
{
    emit windowClosed();
}


// New batch effect class
BatchEffect::BatchEffect(UIManager *manager, PixieBrowser *browser,
                         QStringList &files, int effectType)
    : QObject()
{
    type = effectType;
    mgr = manager;
    view = browser;
    fileList = files;
    textImage = NULL;

    if(type == Grayscale || type == Invert || type == FlipH ||
       type == FlipV || type == Rot90 || type == Rot180 || type == Rot270 ||
       type == AddText || type == Scale || type == Border)
        useQt = true;
    else
        useQt = false;
}

BatchEffect::~BatchEffect()
{
    if(textImage)
        delete textImage;
}

bool BatchEffect::apply()
{
    if(!getParameters())
        return(false);

    int previewType = KMessageBox::questionYesNoCancel(view,
                                                       i18n("Do you want to preview effects before applying?"),
                                                       i18n("Preview Selection"));
    if(previewType == KMessageBox::Cancel)
        return(false);

    if(previewType == KMessageBox::No){
        KIFBatchProgressWidget progress(this, NULL);
        if(useQt){
            connect(this, SIGNAL(setProgress(int)), progress.progressBar(),
                    SLOT(setValue(int)));
            connect(this, SIGNAL(setProgressText(const QString &)),
                    progress.progressLabel(), SLOT(setText(const QString &)));
        }
        else
            kifapp()->setMagickMessageWidgets(progress.progressBar(),
                                              progress.progressLabel());
        QStringList::Iterator it;
        bool proceed = true;
        cancel = false;
        for(it = fileList.begin(); it != fileList.end() && proceed && !cancel; ++it){
            progress.setTitle(i18n("Processing: ") + (*it));
            qApp->processEvents();
            if(useQt)
                proceed = applyQtEffect((*it));
            else
                proceed = applyMagickEffect((*it));
        }
        if(!useQt)
            kifapp()->setMagickMessageWidgets(NULL, NULL);
    }
    else{
        KIFBatchPreviewWidget progress(this, NULL);
        if(useQt){
            connect(this, SIGNAL(setProgress(int)), progress.progressBar(),
                    SLOT(setValue(int)));
            connect(this, SIGNAL(setProgressText(const QString &)),
                    progress.progressLabel(), SLOT(setText(const QString &)));
        }
        else
            kifapp()->setMagickMessageWidgets(progress.progressBar(),
                                              progress.progressLabel());
        QStringList::Iterator it;
        bool proceed = true;
        cancel = false;
        for(it = fileList.begin(); it != fileList.end() && proceed && !cancel; ++it){
            progress.setTitle(i18n("Processing: ") + (*it));
            qApp->processEvents();
            if(useQt)
                proceed = applyQtEffect((*it), &progress);
            else
                proceed = applyMagickEffect((*it), &progress);
        }
        if(!useQt)
            kifapp()->setMagickMessageWidgets(NULL, NULL);

    }

    return(true);
}

void BatchEffect::slotCancel()
{
    cancel = true;
}

void BatchEffect::slotAcceptPreview()
{
    acceptPreview = true;
}

void BatchEffect::slotRejectPreview()
{
    rejectPreview = true;
}

bool BatchEffect::applyMagickEffect(const QString &filename,
                                    KIFBatchPreviewWidget *preview)
{
    ExceptionInfo exception;
    ImageInfo *info = CloneImageInfo(NULL);
    Image *img;
    bool save = true;


    if(preview)
        preview->disable();

    GetExceptionInfo(&exception);
    qstrcpy(info->filename, QFile::encodeName(filename));
    img = ReadImage(info, &exception);

    if(!img){
        DestroyImageInfo(info);
        return(KMessageBox::warningContinueCancel(NULL,
                                                  i18n("Cannot open ") + filename + i18n("!"),
                                                  i18n("File Open Error"),
                                                  i18n("Continue"),
                                                  QString::null, true) !=
               KMessageBox::Cancel);
    }

    if(type == Normalize)
        NormalizeImage(img);
    else if(type == Equalize)
        EqualizeImage(img);
    else if(type == IncContrast)
        ContrastImage(img, true);
    else if(type == DecContrast)
        ContrastImage(img, false);
    else if(type == Solarize)
        SolarizeImage(img, weight);
    else if(type == Threshold)
        ThresholdImage(img, weight);
    else if(type == Despeckle){
        Image *tmp = DespeckleImage(img, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Blur){
        Image *tmp = BlurImage(img, radius, sigma, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Emboss){
        Image *tmp = EmbossImage(img, radius, sigma, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Charcoal){
        Image *tmp = CharcoalImage(img, radius, sigma, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Sharpen){
        Image *tmp = SharpenImage(img, radius, sigma, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Edge){
        Image *tmp = EdgeImage(img, weight, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Implode){
        img->background_color.red = ScaleCharToQuantum(bg.red());
        img->background_color.green = ScaleCharToQuantum(bg.green());
        img->background_color.blue = ScaleCharToQuantum(bg.blue());
        Image *tmp = ImplodeImage(img, weight, &exception);
        if(tmp){
             if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == OilPaint){
        Image *tmp = OilPaintImage(img, weight, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Spread){
        Image *tmp = SpreadImage(img, (unsigned int)weight, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Swirl){
        img->background_color.red = ScaleCharToQuantum(bg.red());
        img->background_color.green = ScaleCharToQuantum(bg.green());
        img->background_color.blue = ScaleCharToQuantum(bg.blue());
        Image *tmp = SwirlImage(img, weight, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Shade){
        Image *tmp = ShadeImage(img, useColor, a, e, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == Wave){
        img->background_color.red = ScaleCharToQuantum(bg.red());
        img->background_color.green = ScaleCharToQuantum(bg.green());
        img->background_color.blue = ScaleCharToQuantum(bg.blue());
        Image *tmp = WaveImage(img, a, f, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    else if(type == AddNoise){
        Image *tmp = AddNoiseImage(img, noiseType, &exception);
        if(tmp){
            if(img->next)
                DestroyImageList(img);
            else
                DestroyImage(img);
            img = tmp;
        }
        else
            save = false;
    }
    MagickMonitor(i18n("Finished").latin1(), 100, 100, &exception);

    bool retValue = true;
    if(save){
        bool result;
        if(preview){
            acceptPreview = false;
            rejectPreview = false;
            QImage qImg(img->columns, img->rows, 32);
            DispatchImage(img, 0, 0, img->columns, img->rows,
                          "BGRA", CharPixel, qImg.bits(), &exception);
            preview->setPreviewImage(qImg);
            while(!cancel && !acceptPreview && !rejectPreview)
                qApp->processEvents();
            if(acceptPreview){
                result = WriteImage(info, img);
                if(!result){
                    retValue = KMessageBox::warningContinueCancel(view,
                                                                  i18n("Cannot save ") + filename,
                                                                  i18n("Effect save error!"),
                                                                  i18n("Continue"),
                                                                  QString::null, true) != KMessageBox::Cancel;
                }
            }
        }
        else{
            result = WriteImage(info, img);
            if(!result){
                retValue = KMessageBox::warningContinueCancel(view,
                                                              i18n("Cannot save ") + filename,
                                                              i18n("Effect save error!"),
                                                              i18n("Continue"),
                                                              QString::null, true) == KMessageBox::Cancel;
            }
        }
    }
    if(img->next)
        DestroyImageList(img);
    else
        DestroyImage(img);
    DestroyImageInfo(info);
    return(retValue);
}

bool BatchEffect::applyQtEffect(const QString &filename,
                                KIFBatchPreviewWidget *preview)
{
    QImage img;
    bool save = true;
    char format[32];

    if(preview)
        preview->disable();
    if(type == FlipH || type == FlipV || type == Rot90 || type == Rot180 ||
       type == Rot270){
        const char *ext = extension(QFile::encodeName(filename));
        if(ext){
            if(qstricmp(ext, "jpg") == 0 || qstricmp(ext, "jpeg") == 0){
                // do lossless JPEG rotation
                QBuffer buffer;
                JPEGTransform t;
                switch(type){
                case FlipH:
                    t = JPEGFlipH;
                    break;
                case FlipV:
                    t = JPEGFlipV;
                    break;
                case Rot90:
                    t = JPEGRot90;
                    break;
                case Rot180:
                    t = JPEGRot180;
                    break;
                case Rot270:
                    t = JPEGRot270;
                    break;
                default:
                    t = JPEGFlipH;
                    break;
                }
                if(type == FlipH || type == FlipV)
                    emit setProgressText(i18n("Lossless JPEG Flipping..."));
                else
                    emit setProgressText(i18n("Loseless JPEG Rotating..."));
                emit setProgress(0);
                qApp->processEvents();
                if(transformJPEG(QFile::encodeName(filename), &buffer, t)){
                    qWarning("JPEG transform success!");
                    emit setProgress(100);
                    emit setProgressText(i18n("Finished"));
                    qApp->processEvents();
                    buffer.close();
                    if(buffer.size() != 0 &&
                       img.loadFromData(buffer.buffer(), "JPEG")){
                        if(preview){
                            acceptPreview = false;
                            rejectPreview = false;
                            preview->setPreviewImage(img);
                            while(!cancel && !acceptPreview && !rejectPreview)
                                qApp->processEvents();
                            if(acceptPreview){
                                QFile file(QFile::encodeName(filename));
                                if(file.open(IO_WriteOnly | IO_Truncate)){
                                    file.writeBlock(buffer.buffer());
                                    file.close();
                                    return(true);
                                }
                                else{
                                    qWarning("Unable to save image");
                                    if(KMessageBox::warningContinueCancel(view,
                                                                          i18n("Cannot save ") + filename,
                                                                          i18n("Effect save error!"),
                                                                          i18n("Continue"),
                                                                          QString::null, true) ==
                                       KMessageBox::Cancel)
                                        return(false);
                                    return(true);
                                }
                            }
                            else
                                return(true);
                        }
                        else{
                            QFile file(QFile::encodeName(filename));
                            if(file.open(IO_WriteOnly | IO_Truncate)){
                                file.writeBlock(buffer.buffer());
                                file.close();
                                return(true);
                            }
                            else{
                                qWarning("Unable to save image");
                                if(KMessageBox::warningContinueCancel(view,
                                                                      i18n("Cannot save ") + filename,
                                                                      i18n("Effect save error!"),
                                                                      i18n("Continue"),
                                                                      QString::null, true) ==
                                   KMessageBox::Cancel)
                                    return(false);
                                return(true);
                            }
                            return(true);
                        }
                    }
                }
                qWarning("Lossless JPEG transform failed, trying normal effect.");
            }
        }
    }
    // Normal effect

    if(!loadImage(img, filename, NULL, format)){
        return(KMessageBox::warningContinueCancel(NULL,
                                                  i18n("Cannot open ") + filename + i18n("!"),
                                                  i18n("File Open Error"),
                                                  i18n("Continue"),
                                                  QString::null, true) !=
               KMessageBox::Cancel);
    }

    if(type == AddText){
        emit setProgressText(i18n("Applying text..."));
        // progress bar is kindof dumb here since it just goes from 0->100,
        // but we use it to be consistent w/ the ImageMagick effects that
        // display much more ;-)
        emit setProgress(0);
        qApp->processEvents();
        if(img.depth() < 32)
            img = img.convertDepth(32);
        save = applyTextLabel(textPos, *textImage, img);
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }
    else if(type == Scale){
        if(img.width() > newW || img.height() > newH){
            emit setProgressText(i18n("Smoothscaling..."));
            emit setProgress(0);
            qApp->processEvents();
            if(img.width() > img.height()){
                float percent = (((float)newW)/img.width());
                int h = (int)(img.height()*percent);
                img = img.smoothScale(newW, h);
            }
            else{
                float percent = (((float)newH)/img.height());
                int w = (int)(img.width()*percent);
                img = img.smoothScale(w, newH);
            }
            emit setProgress(100);
            emit setProgressText(i18n("Finished"));
            qApp->processEvents();
        }
        else{
            emit setProgressText(i18n("No resize needed"));
            qApp->processEvents();
            save = false;
        }
    }
    else if(type == Border){
        emit setProgressText(i18n("Applying border..."));
        emit setProgress(0);
        qApp->processEvents();
        QImage tmpImg;
        if(img.depth() < 32)
            img = img.convertDepth(32);
        if(borderType == Solid){
            KIFBorderEffect::solid(img, tmpImg, fg, borderWidth);
        }
        else if(borderType == Bevel){
            KIFBorderEffect::bevel(img, tmpImg, fg, bg, borderWidth);
        }
        else if(borderType == Liquid){
            KIFBorderEffect::liquid(img, tmpImg, fg, bg, borderWidth);
        }
        else if(borderType == RoundCorner){
            KIFBorderEffect::roundCorner(img, tmpImg, bg);
        }
        img = tmpImg;
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }
    else if(type == Grayscale){
        emit setProgressText(i18n("Grayscaling..."));
        emit setProgress(0);
        qApp->processEvents();
        KImageEffect::toGray(img);
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }
    else if(type == Invert){
        emit setProgressText(i18n("Inverting..."));
        emit setProgress(0);
        qApp->processEvents();
        img.invertPixels(false);
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }
    else if(type == FlipH){
        emit setProgressText(i18n("Flipping..."));
        emit setProgress(0);
        qApp->processEvents();
        img = img.mirror(true, false);
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }
    else if(type == FlipV){
        emit setProgressText(i18n("Flipping..."));
        emit setProgress(0);
        qApp->processEvents();
        img = img.mirror(false, true);
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }
    else if(type == Rot90){
        emit setProgressText(i18n("Rotating..."));
        emit setProgress(0);
        qApp->processEvents();
        img = KImageEffect::rotate(img, KImageEffect::Rotate90);
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }
    else if(type == Rot180){
        emit setProgressText(i18n("Rotating..."));
        emit setProgress(0);
        qApp->processEvents();
        img = KImageEffect::rotate(img, KImageEffect::Rotate180);
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }
    else if(type == Rot270){
        emit setProgressText(i18n("Rotating..."));
        emit setProgress(0);
        qApp->processEvents();
        img = KImageEffect::rotate(img, KImageEffect::Rotate270);
        emit setProgress(100);
        emit setProgressText(i18n("Finished"));
        qApp->processEvents();
    }

    if(save){
        if(preview){
            acceptPreview = false;
            rejectPreview = false;
            preview->setPreviewImage(img);
            while(!cancel && !acceptPreview && !rejectPreview)
                qApp->processEvents();
            if(acceptPreview){
                if(!saveImage(img, filename, format)){
                    qWarning("Unable to save image");
                    if(KMessageBox::warningContinueCancel(view,
                                                          i18n("Cannot save ") + filename,
                                                          i18n("Effect save error!"),
                                                          i18n("Continue"),
                                                          QString::null, true) ==
                       KMessageBox::Cancel)
                        return(false);
                    return(true);
                }
            }
        }
        else{
            if(!saveImage(img, filename, format)){
                qWarning("Unable to save image");
                if(KMessageBox::warningContinueCancel(view,
                                                      i18n("Cannot save ") + filename,
                                                      i18n("Effect save error!"),
                                                      i18n("Continue"),
                                                      QString::null, true) ==
                   KMessageBox::Cancel)
                    return(false);
                return(true);
            }
        }
    }
    return(true);
}

bool BatchEffect::getParameters()
{
    // QImage effects
    if(type == AddText){
        KIFTextDialog dlg(view);
        if(dlg.exec() == QDialog::Accepted){
            textImage = new QImage();
            createTextLabel(dlg.text(), dlg.color(), dlg.font(),
                            *textImage);
            textPos = dlg.pos();
            return(true);
        }
        return(false);
    }
    else if(type == Scale){
        KIFSizeDialog dlg(600, 500, view);
        if(dlg.exec() == QDialog::Accepted){
            newW = dlg.resultWidth();
            newH = dlg.resultHeight();
            return(true);
        }
        return(false);
    }
    else if(type == Border){
        KIFBorderDialog dlg(view);
        if(dlg.exec() == QDialog::Accepted){
            borderType = dlg.borderType();
            borderWidth = dlg.borderWidth();
            fg = dlg.fgColor();
            bg = dlg.bgColor();
            return(true);
        }
        return(false);
    }
    // Magick effects
    else if(type == AddNoise){
        QStringList typeList;
        typeList.append(i18n("Uniform"));
        typeList.append(i18n("Gaussian"));
        typeList.append(i18n("Multiplicative Gaussian"));
        typeList.append(i18n("Impulse"));
        typeList.append(i18n("Laplacian"));
        typeList.append(i18n("Poisson"));
        bool ok;
        QString type = QInputDialog::getItem(i18n("Noise Type"),
                                       i18n("Please select a noise type."),
                                       typeList, 0, false, &ok, view);
        if(!ok)
            return(false);
        if(type == i18n("Uniform"))
            noiseType = UniformNoise;
        else if(type == i18n("Gaussian"))
            noiseType = GaussianNoise;
        else if(type == i18n("Multiplicative Gaussian"))
            noiseType = MultiplicativeGaussianNoise;
        else if(type == i18n("Impulse"))
            noiseType = ImpulseNoise;
        else if(type == i18n("Laplacian"))
            noiseType = LaplacianNoise;
        else if(type == i18n("Poisson"))
            noiseType = PoissonNoise;
        return(true);
    }
    else if(type == Wave){
        KIFSineWaveDialog dlg(view);
        if(dlg.exec() == QDialog::Accepted){
            a = dlg.amplitude();
            f = dlg.frequency();
            KColorDialog dlg(NULL, NULL, true);
            dlg.setCaption(i18n("Select a Background Color"));
            dlg.setColor(Qt::white);
            if(dlg.exec() != QDialog::Accepted)
                return(false);
            else{
                bg = dlg.color();
                return(true);
            }
        }
        return(false);
    }
    else if(type == Shade){
        KIFShadeDialog dlg(view);
        if(dlg.exec() == QDialog::Accepted){
            a = dlg.azimuth();
            e = dlg.elevation();
            useColor = dlg.colorShading();
            return(true);
        }
        return(false);
    }
    else if(type == Emboss){
        return(getRadiusAndDeviation(i18n("Please enter the emboss radius and standard deviation:"),
                                     radius, sigma, view));
    }
    else if(type == Charcoal){
        return(getRadiusAndDeviation(i18n("Please enter the charcoal radius and standard deviation:"),
                                     radius, sigma, view));
    }
    else if(type == Sharpen){
        return(getRadiusAndDeviation(i18n("Please enter the sharpen radius and standard deviation:"),
                                     radius, sigma, view));
    }
    else if(type == Blur){
        return(getRadiusAndDeviation(i18n("Please enter the blur radius and standard deviation:"),
                                     radius, sigma, view));
    }
    else if(type == Edge){
        bool ok;
        weight = QInputDialog::getDouble(i18n("Edge Detect Radius"),
                                         i18n("Please enter the edge detect radius (0=use default)"),
                                         0, 0, 10, 1, &ok, view);
        return(ok);
    }
    else if(type == ReduceNoise){
        bool ok;
        weight = QInputDialog::getDouble(i18n("Reduce Noise Radius"),
                                         i18n("Please enter the noise radius (0=use default)"),
                                         0, 0, 10, 1, &ok, view);
        return(ok);
    }
    else if(type == OilPaint){
        bool ok;
        weight = QInputDialog::getDouble(i18n("Oil Paint Radius"),
                                         i18n("Please enter the oil paint radius (0=use default)"),
                                         0, 0, 10, 1, &ok, view);
        return(ok);
    }
    else if(type == Solarize){
        bool ok;
        weight = QInputDialog::getInteger(i18n("Solarization Factor"),
                                          i18n("Please enter the solarization factor (0-65565)"),
                                          100, 0, MaxRGB, 1, &ok, view);
        return(ok);
    }
    else if(type == Swirl){
        bool ok;
        weight = QInputDialog::getDouble(i18n("Swirl Angle"),
                                         i18n("Please enter angle to swirl"),
                                         60, 1, 360, 1, &ok, view);
        if(ok){
            KColorDialog dlg(NULL, NULL, true);
            dlg.setCaption(i18n("Select a Background Color"));
            dlg.setColor(Qt::white);
            if(dlg.exec() != QDialog::Accepted)
                return(false);
            else{
                bg = dlg.color();
                return(true);
            }
        }
        return(false);
    }
    else if(type == Implode){
        bool ok;
        weight = QInputDialog::getDouble(i18n("Implode Factor"),
                                         i18n("Please enter factor to implode (-1.0 - 1.0)"),
                                         0.3, -1.0, 1.0, 1, &ok, view);
        if(ok){
            KColorDialog dlg(NULL, NULL, true);
            dlg.setCaption(i18n("Select a Background Color"));
            dlg.setColor(Qt::white);
            if(dlg.exec() != QDialog::Accepted)
                return(false);
            else{
                bg = dlg.color();
                return(true);
            }
        }
        return(false);
    }
    else if(type == Threshold){
        bool ok;
        weight = QInputDialog::getInteger(i18n("Threshold"),
                                          i18n("Please enter the threshold value"),
                                          128, 0, 255, 1, &ok, view);
        return(ok);
    }
    else if(type == Spread){
        bool ok;
        weight = QInputDialog::getInteger(i18n("Displacement Amount"),
                                          i18n("Please enter the displacement amount"),
                                          2, 1, 30, 1, &ok, view);
        return(ok);
    }

    return(true);
}

