/* ============================================================
 *
 * This file is a part of kipi-plugins project
 * http://www.kipi-plugins.org
 *
 * Date        : 2004-10-01
 * Description : a kipi plugin to batch process images
 *
 * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General
 * Public License as published by the Free Software Foundation;
 * either version 2, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * ============================================================ */
 
// C Ansi includes

extern "C"
{
#include <unistd.h>
}

// C++ includes.

#include <cstdlib>

// TQt includes

#include <tqpixmap.h>
#include <tqpushbutton.h>
#include <tqvbox.h>
#include <tqlayout.h>
#include <tqgroupbox.h>
#include <tqlabel.h>
#include <tqslider.h>
#include <tqlcdnumber.h>
#include <tqpainter.h>
#include <tqwhatsthis.h>
#include <tqapplication.h>
#include <tqcursor.h>

// KDE includes

#include <kprocess.h>
#include <tdemessagebox.h>
#include <kurl.h>
#include <tdeio/job.h>
#include <tdeio/jobclasses.h>
#include <tdeio/netaccess.h>
#include <tdeio/global.h>
#include <tdelocale.h>
#include <kstandarddirs.h>
#include <kcursor.h>
#include <kdebug.h>
#include <tdeapplication.h>
#include <khelpmenu.h>
#include <kiconloader.h>
#include <tdepopupmenu.h>

// Local includes

#include "kpaboutdata.h"
#include "pluginsversion.h"
#include "imagepreview.h"
#include "imagepreview.moc"

namespace KIPIBatchProcessImagesPlugin
{

int INIT_ZOOM_FACTOR;

ImagePreview::ImagePreview(const TQString &fileOrig, const TQString &fileDest, const TQString &tmpPath,
                           bool cropActionOrig, bool cropActionDest, const TQString &EffectName,
                           const TQString &FileName, TQWidget *parent)
            : KDialogBase( parent, "PreviewDialog", true, i18n("Batch Process Preview (%1 - %2)").arg(EffectName)
                           .arg(FileName), Help|Ok, Ok, true)
{
    // About data and help button.

    m_about = new KIPIPlugins::KPAboutData(I18N_NOOP("Batch process images"),
                                           0,
                                           TDEAboutData::License_GPL,
                                           I18N_NOOP("An interface to preview the \"Batch Process Images\" "
                                                     "Kipi plugin.\n"
                                                     "This plugin uses the \"convert\" program from \"ImageMagick\" "
                                                     "package."),
                                           "(c) 2003-2004, Gilles Caulier");

    m_about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"),
                     "caulier dot gilles at gmail dot com");

    m_helpButton = actionButton( Help );
    KHelpMenu* helpMenu = new KHelpMenu(this, m_about, false);
    helpMenu->menu()->removeItemAt(0);
    helpMenu->menu()->insertItem(i18n("Plugin Handbooks"), this, TQ_SLOT(slotHelp()), 0, -1, 0);
    m_helpButton->setPopup( helpMenu->menu() );

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

    TQWidget* box = new TQWidget( this );
    setMainWidget(box);
    resize(700, 400);

    if ( cropActionOrig == true || cropActionDest == true )
        INIT_ZOOM_FACTOR = 20;
    else
        INIT_ZOOM_FACTOR = 5;

    TQVBoxLayout* ml = new TQVBoxLayout( box, 10 );

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

    TQHBoxLayout* h1 = new TQHBoxLayout( ml );
    TQVBoxLayout* v1 = new TQVBoxLayout( h1 );
    h1->addSpacing( 5 );
    TQGridLayout* g1 = new TQGridLayout( v1, 1, 2 );

    TQGroupBox * groupBoxZoomFactor = new TQGroupBox( 2, TQt::Horizontal, i18n("Zoom Factor"), box );
    LCDZoomFactorValue = new TQLCDNumber (4, groupBoxZoomFactor, "ZoomFactorLCDvalue");
    LCDZoomFactorValue->setSegmentStyle ( TQLCDNumber::Flat );
    LCDZoomFactorValue->display( TQString::number(INIT_ZOOM_FACTOR * 5) );
    TQWhatsThis::add( LCDZoomFactorValue, i18n("<p>The zoom factor value, as a percentage."));

    ZoomFactorSlider = new TQSlider (1, 20, 1, INIT_ZOOM_FACTOR, TQt::Horizontal,
                                    groupBoxZoomFactor, "ZoomFactorSlider");
    ZoomFactorSlider->setTracking ( false );
    ZoomFactorSlider->setTickInterval ( 5 );
    TQWhatsThis::add( ZoomFactorSlider, i18n("<p>Moving this slider changes the zoom factor value."));
    g1->addWidget( groupBoxZoomFactor, 0, 0);

    TQGridLayout* g2 = new TQGridLayout( v1, 1, 2 );
    TQGroupBox * groupBox1 = new TQGroupBox( 1, TQt::Horizontal, i18n("Original Image"), box );
    m_previewOrig = new PixmapView(cropActionOrig, groupBox1);
    TQWhatsThis::add( m_previewOrig, i18n("<p>This is the original image preview. You can use the mouse "
                                         "wheel to change the zoom factor. Click in and use the mouse "
                                         "to move the image."));
    g2->addWidget( groupBox1 , 0, 0);

    TQGroupBox * groupBox2 = new TQGroupBox( 1, TQt::Horizontal, i18n("Destination Image"), box );
    m_previewDest = new PixmapView(cropActionDest, groupBox2);
    TQWhatsThis::add( m_previewDest, i18n("<p>This is the destination image preview. You can use the "
                                         "mouse wheel to change the zoom factor. Click in and use the "
                                         "mouse to move the image."));
    g2->setColStretch(0,1);
    g2->setColStretch(1,1);
    g2->addWidget( groupBox2 , 0, 1);

    connect( ZoomFactorSlider, TQ_SIGNAL(valueChanged(int)),
             this, TQ_SLOT(slotZoomFactorValueChanged(int)) );

    connect( m_previewOrig, TQ_SIGNAL(wheelEvent(int)),
             this, TQ_SLOT(slotWheelChanged(int)) );

    connect( m_previewDest, TQ_SIGNAL(wheelEvent(int)),
             this, TQ_SLOT(slotWheelChanged(int)) );

    m_previewOrig->setImage(fileOrig, tmpPath);
    m_previewDest->setImage(fileDest, tmpPath);
}

ImagePreview::~ImagePreview()
{
    delete m_about;
}

void ImagePreview::slotHelp( void )
{
    TDEApplication::kApplication()->invokeHelp("", "kipi-plugins");
}

void ImagePreview::slotWheelChanged( int delta )
{
    if ( delta > 0 )
        ZoomFactorSlider->setValue ( ZoomFactorSlider->value() - 1 );
    else
        ZoomFactorSlider->setValue ( ZoomFactorSlider->value() + 1 );

    slotZoomFactorValueChanged( ZoomFactorSlider->value() );
}

void ImagePreview::slotZoomFactorValueChanged( int ZoomFactorValue )
{
    LCDZoomFactorValue->display( TQString::number(ZoomFactorValue * 5) );

    m_previewOrig->resizeImage( ZoomFactorValue * 5 );
    m_previewDest->resizeImage( ZoomFactorValue * 5 );
}

PixmapView::PixmapView(bool cropAction, TQWidget *parent, const char *name)
           : TQScrollView(parent, name)
{
    m_cropAction = cropAction;
    m_pix = NULL;
    m_validPreview = false;
    setMinimumSize(TQSize(300,300));
    horizontalScrollBar()->setLineStep( 1 );
    horizontalScrollBar()->setPageStep( 1 );
    verticalScrollBar()->setLineStep( 1 );
    verticalScrollBar()->setPageStep( 1 );
    TDEGlobal::dirs()->addResourceType("kipi_handcursor", TDEGlobal::dirs()->kde_default("data")
                   + "kipi/data");
    m_handCursor = new TQCursor( TDEGlobal::dirs()->findResourceDir("kipi_handcursor", "handcursor.png")
                   + "handcursor.png" );
}

PixmapView::~PixmapView()
{
    if(m_pix) delete m_pix;
}

void PixmapView::setImage(const TQString &ImagePath, const TQString &tmpPath)
{

    m_previewFileName = tmpPath + "/" + TQString::number(getpid()) + "-"
                        + TQString::number(random()) + "PreviewImage.PNG";

    if (m_cropAction == true)
       PreviewCal(ImagePath, tmpPath);
    else
       {
       if ( m_img.load(ImagePath) == false )
          PreviewCal(ImagePath, tmpPath);
       else
          {
          if(!m_pix) m_pix = new TQPixmap(m_img.width(), m_img.height());
          m_w = m_img.width();
          m_h = m_img.height();
          m_validPreview = true;
          resizeImage( INIT_ZOOM_FACTOR *5 );
          horizontalScrollBar()->setLineStep(1);
          verticalScrollBar()->setLineStep(1);
          }
       }
}

void PixmapView::PreviewCal(const TQString &ImagePath, const TQString &/*tmpPath*/)
{
    m_pix = new TQPixmap(300, 300);
    TQPainter p;
    p.begin(m_pix);
    p.fillRect(0, 0, m_pix->width(), m_pix->height(), TQt::white);
    p.setPen(TQt::green);
    p.drawText(0, 0, m_pix->width(), m_pix->height(), TQt::AlignCenter,
               i18n("Preview\nimage\nprocessing\nin\nprogress..."));
    p.end();

    m_previewOutput ="convert";
    m_PreviewProc = new TDEProcess;
    *m_PreviewProc << "convert";
    *m_PreviewProc << "-verbose";

    if (m_cropAction == true)
       {
       *m_PreviewProc << "-crop" << "300x300+0+0";
       m_previewOutput.append( " -crop 300x300+0+0 " );
       }

    *m_PreviewProc << ImagePath;
    *m_PreviewProc << m_previewFileName;
    m_previewOutput.append( " -verbose " + ImagePath + " " + m_previewFileName + "\n\n");

    connect(m_PreviewProc, TQ_SIGNAL(processExited(TDEProcess *)),
            this, TQ_SLOT(PreviewProcessDone(TDEProcess*)));

    connect(m_PreviewProc, TQ_SIGNAL(receivedStdout(TDEProcess *, char*, int)),
            this, TQ_SLOT(slotPreviewReadStd(TDEProcess*, char*, int)));

    connect(m_PreviewProc, TQ_SIGNAL(receivedStderr(TDEProcess *, char*, int)),
            this, TQ_SLOT(slotPreviewReadStd(TDEProcess*, char*, int)));

    bool result = m_PreviewProc->start(TDEProcess::NotifyOnExit, TDEProcess::All);
    if(!result)
    {
        KMessageBox::error(this, i18n("Cannot start 'convert' program from 'ImageMagick' package;\n"
                                      "please check your installation."));
        return;
    }
}

void PixmapView::slotPreviewReadStd(TDEProcess* /*proc*/, char *buffer, int buflen)
{
    m_previewOutput.append( TQString::fromLocal8Bit(buffer, buflen) );
}

void PixmapView::PreviewProcessDone(TDEProcess* proc)
{
    int ValRet = proc->exitStatus();
    kdDebug (51000) << "Convert exit (" << ValRet << ")" << endl;

    if ( ValRet == 0 )
       {
       if ( m_img.load( m_previewFileName ) == true )
          {
          if(!m_pix) m_pix = new TQPixmap(300, 300);
          m_w = m_img.width();
          m_h = m_img.height();
          m_validPreview = true;
          resizeImage( INIT_ZOOM_FACTOR * 5 );
          horizontalScrollBar()->setLineStep(1);
          verticalScrollBar()->setLineStep(1);
          KURL deletePreviewImage( m_previewFileName );
          TDEIO::NetAccess::del( deletePreviewImage, kapp->activeWindow() );
          }
       else
          {
          m_pix = new TQPixmap(visibleWidth(), visibleHeight());
          TQPainter p;
          p.begin(m_pix);
          p.fillRect(0, 0, m_pix->width(), m_pix->height(), TQt::white);
          p.setPen(TQt::red);
          p.drawText(0, 0, m_pix->width(), m_pix->height(), TQt::AlignCenter,
                     i18n("Cannot\nprocess\npreview\nimage."));
          p.end();
          repaintContents();
          m_validPreview = false;
          }
       }
}

void PixmapView::resizeImage(int ZoomFactor)
{
    if ( m_validPreview == false) return;

    int w = m_w - (int)((float)m_w * (100-(float)ZoomFactor) / 100);
    int h = m_h - (int)((float)m_h * (100-(float)ZoomFactor) / 100);

    TQImage imgTmp = m_img.scale(w, h);
    m_pix->convertFromImage(imgTmp);
    resizeContents(w, h);
    repaintContents(false);
}

void PixmapView::drawContents(TQPainter *p, int x, int y, int w, int h)
{
    if(!m_pix) return;
    else p->drawPixmap(x, y, *m_pix, x, y, w, h);
}

void PixmapView::contentsWheelEvent( TQWheelEvent * e )
{
    emit wheelEvent(e->delta());
}

void PixmapView::contentsMousePressEvent ( TQMouseEvent * e )
{
    if ( e->button() == TQt::LeftButton )
       {
       m_xpos = e->x();
       m_ypos = e->y();
       setCursor ( *m_handCursor );
       }
}

void PixmapView::contentsMouseReleaseEvent ( TQMouseEvent * /*e*/ )
{
    setCursor ( KCursor::arrowCursor() );
}

void PixmapView::contentsMouseMoveEvent( TQMouseEvent * e )
{
     if ( e->state() == TQt::LeftButton )
     {
         uint newxpos = e->x();
         uint newypos = e->y();

         scrollBy (-(newxpos - m_xpos), -(newypos - m_ypos));

         m_xpos = newxpos - (newxpos-m_xpos);
         m_ypos = newypos - (newypos-m_ypos);
     }
}

}  // NameSpace KIPIBatchProcessImagesPlugin
