/*
 *  kis_tool_transform.cpp -- part of Chalk
 *
 *  Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
 *
 *  Based on the transform tool from :
 *  Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
 *  Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
 *
 *  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; version 2 of the License.
 *
 *  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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "kis_tool_perspectivetransform.h"


#include <tqpainter.h>
#include <tqpen.h>
#include <tqpushbutton.h>
#include <tqobject.h>
#include <tqlabel.h>
#include <tqcombobox.h>
#include <tqapplication.h>

#include <kdebug.h>
#include <tdeaction.h>
#include <kcommand.h>
#include <tdelocale.h>
#include <knuminput.h>

#include <kis_global.h>
#include <kis_painter.h>
#include <kis_canvas_controller.h>
#include <kis_canvas_subject.h>
#include <kis_cursor.h>
#include <kis_image.h>
#include <kis_undo_adapter.h>
#include <kis_selected_transaction.h>
#include <kis_button_press_event.h>
#include <kis_button_release_event.h>
#include <kis_move_event.h>
#include <kis_selection.h>
#include <kis_filter_strategy.h>
#include <kis_cmb_idlist.h>
#include <kis_id.h>
#include <kis_tool_controller.h>
#include <kis_perspectivetransform_worker.h>

//#include "wdg_tool_transform.h"
#include "kis_canvas.h"
#include "kis_canvas_painter.h"

namespace {
    class PerspectiveTransformCmd : public KisSelectedTransaction {
        typedef KisSelectedTransaction super;

    public:
        PerspectiveTransformCmd(KisToolPerspectiveTransform *tool, KisPaintDeviceSP device, KisPaintDeviceSP origDevice,  KisPoint topleft, KisPoint topright, KisPoint bottomleft, KisPoint bottomright, KisSelectionSP origSel, TQRect initialRect);
        virtual ~PerspectiveTransformCmd();

    public:
        virtual void execute();
        virtual void unexecute();
        void transformArgs(KisPoint &topleft, KisPoint &topright, KisPoint &bottomleft, KisPoint& bottomright) const;
        KisSelectionSP origSelection(TQRect& initialRect) const;
        KisPaintDeviceSP theDevice();
        KisPaintDeviceSP origDevice();

    private:
        TQRect m_initialRect;
        KisPoint m_topleft, m_topright, m_bottomleft, m_bottomright;
        KisToolPerspectiveTransform *m_tool;
        KisSelectionSP m_origSelection;
        KisPaintDeviceSP m_device;
        KisPaintDeviceSP m_origDevice;
    };

    PerspectiveTransformCmd::PerspectiveTransformCmd(KisToolPerspectiveTransform *tool, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, KisPoint topleft, KisPoint topright, KisPoint bottomleft, KisPoint bottomright, KisSelectionSP origSel, TQRect initialRect) :
            super(i18n("Perspective Transform"), device), m_initialRect(initialRect)
            , m_topleft(topleft), m_topright(topright), m_bottomleft(bottomleft), m_bottomright(bottomright)
            , m_tool(tool), m_origSelection(origSel), m_device(device), m_origDevice(origDevice)
    {
    }

    PerspectiveTransformCmd::~PerspectiveTransformCmd()
    {
    }

    void PerspectiveTransformCmd::transformArgs(KisPoint &topleft, KisPoint &topright, KisPoint &bottomleft, KisPoint& bottomright) const
    {
        topleft = m_topleft;
        topright = m_topright;
        bottomleft = m_bottomleft;
        bottomright = m_bottomright;
    }

    KisSelectionSP PerspectiveTransformCmd::origSelection(TQRect& initialRect) const
    {
        initialRect = m_initialRect;
        return m_origSelection;
    }

    void PerspectiveTransformCmd::execute()
    {
        super::execute();
    }

    void PerspectiveTransformCmd::unexecute()
    {
        super::unexecute();
    }

    KisPaintDeviceSP PerspectiveTransformCmd::theDevice()
    {
        return m_device;
    }

    KisPaintDeviceSP PerspectiveTransformCmd::origDevice()
    {
        return m_origDevice;
    }
}

KisToolPerspectiveTransform::KisToolPerspectiveTransform()
    : super(i18n("Perspective Transform"))
{
    setName("tool_perspectivetransform");
    setCursor(KisCursor::selectCursor());
    m_subject = 0;
    m_origDevice = 0;
    m_origSelection = 0;
    m_handleHalfSize = 8;
    m_handleSize = 2 * m_handleHalfSize;
    m_handleSelected = NOHANDLE;
}

KisToolPerspectiveTransform::~KisToolPerspectiveTransform()
{
}

void KisToolPerspectiveTransform::deactivate()
{
    if (m_subject && m_subject->undoAdapter()) m_subject->undoAdapter()->removeCommandHistoryListener( this );

    KisImageSP img = m_subject->currentImg();
    if (!img) return;

    paintOutline();

   disconnect(m_subject->currentImg().data(), TQ_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQ_SLOT(slotLayerActivated(KisLayerSP)));
}

void KisToolPerspectiveTransform::activate()
{
    super::activate();
    m_currentSelectedPoint = 0;
    if(m_subject && m_subject->currentImg() && m_subject->currentImg()->activeDevice())
    {
        //connect(m_subject, commandExecuted(KCommand *c), this, notifyCommandAdded( KCommand * c));
        m_subject->undoAdapter()->setCommandHistoryListener( this );

//         KisToolControllerInterface *controller = m_subject->toolController();
//         if (controller)
//             controller->setCurrentTool(this);

        PerspectiveTransformCmd * cmd=0;

        if(m_subject->currentImg()->undoAdapter()->presentCommand())
            cmd = dynamic_cast<PerspectiveTransformCmd*>(m_subject->currentImg()->undoAdapter()->presentCommand());

        // One of our commands is on top
        if(cmd &&cmd->theDevice() == m_subject->currentImg()->activeDevice())
        {
            m_interractionMode = EDITRECTINTERRACTION;
            // and it even has the same device
            // We should ask for tool args and orig selection
            m_origDevice = cmd->origDevice();
            cmd->transformArgs(m_topleft, m_topright, m_bottomleft, m_bottomright);
            m_origSelection = cmd->origSelection(m_initialRect);
            paintOutline();
        }
        else
        {
            m_interractionMode = DRAWRECTINTERRACTION;
            m_points.clear();
            initHandles();
        }
    }
    connect(m_subject->currentImg(), TQ_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQ_SLOT(slotLayerActivated(KisLayerSP)));
}

void KisToolPerspectiveTransform::initHandles()
{
//     TQ_INT32 x,y,w,h;
    KisImageSP img = m_subject->currentImg();

    KisPaintDeviceSP dev = img->activeDevice();
    if (!dev ) return;

    // Create a lazy copy of the current state
    m_origDevice = new KisPaintDevice(*dev.data());
    Q_ASSERT(m_origDevice);

    if(dev->hasSelection())
    {
        KisSelectionSP sel = dev->selection();
        m_origSelection = new KisSelection(*sel.data());
        m_initialRect = sel->selectedExactRect();
    }
    else {
        m_initialRect = dev->exactBounds();
    }
    m_topleft = KisPoint(m_initialRect.topLeft());
    m_topright = KisPoint(m_initialRect.topRight());
    m_bottomleft = KisPoint(m_initialRect.bottomLeft());
    m_bottomright = KisPoint(m_initialRect.bottomRight());

    m_subject->canvasController() ->updateCanvas();
}

void KisToolPerspectiveTransform::paint(KisCanvasPainter& gc)
{
    paintOutline(gc, TQRect());
}

void KisToolPerspectiveTransform::paint(KisCanvasPainter& gc, const TQRect& rc)
{
    paintOutline(gc, rc);
}

bool KisToolPerspectiveTransform::mouseNear(const TQPoint& mousep, const TQPoint point)
{
    return (TQRect( (point.x() - m_handleHalfSize), (point.y() - m_handleHalfSize), m_handleSize, m_handleSize).contains(mousep) );
}

void KisToolPerspectiveTransform::buttonPress(KisButtonPressEvent *event)
{
    if (m_subject) {
        switch(m_interractionMode)
        {
            case DRAWRECTINTERRACTION:
            {
                if (m_points.isEmpty())
                {
                    m_dragging = false;
                    m_dragStart = event->pos();
                    m_dragEnd = event->pos();
                    m_points.append(m_dragStart);
                    paintOutline();
                } else {
                    m_dragging = true;
                    m_dragStart = m_dragEnd;
                    m_dragEnd = event->pos();
                    paintOutline();
                }
            }
            case EDITRECTINTERRACTION:
            {
                KisImageSP img = m_subject->currentImg();

                if (img && img->activeDevice() && event->button() == TQt::LeftButton) {
                    m_actualyMoveWhileSelected = false;
                    m_dragEnd = event->pos();
                    KisCanvasController *controller = m_subject->canvasController();
                    TQPoint mousep = controller->windowToView( event->pos().roundTQPoint() );
                    if( mouseNear( mousep, controller->windowToView(m_topleft.roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS TOPLEFT HANDLE " << endl;
                        m_currentSelectedPoint = &m_topleft;
                    }
                    else if( mouseNear( mousep, controller->windowToView(m_topright.roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS TOPRIGHT HANDLE " << endl;
                        m_currentSelectedPoint = &m_topright;
                    }
                    else if( mouseNear( mousep, controller->windowToView(m_bottomleft.roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS BOTTOMLEFT HANDLE " << endl;
                        m_currentSelectedPoint = &m_bottomleft;
                    }
                    else if( mouseNear( mousep, controller->windowToView(m_bottomright.roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS BOTTOMRIGHT HANDLE " << endl;
                        m_currentSelectedPoint = &m_bottomright;
                    } else if( mouseNear( mousep, controller->windowToView(KisPoint((m_topleft+m_topright)*0.5).roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS TOP HANDLE " << endl;
                        m_handleSelected = TOPHANDLE;
                    }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_topleft+m_bottomleft)*0.5).roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS LEFT HANDLE " << endl;
                        m_handleSelected = LEFTHANDLE;
                    }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_bottomleft+m_bottomright)*0.5).roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS BOTTOM HANDLE " << endl;
                        m_handleSelected = BOTTOMHANDLE;
                    }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_bottomright+m_topright)*0.5).roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS RIGHT HANDLE " << endl;
                        m_handleSelected = RIGHTHANDLE;
                    }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_topleft+m_bottomleft + m_bottomright+m_topright)*0.25).roundTQPoint() ) ) )
                    {
                        kdDebug() << " PRESS MIDDLE HANDLE " << endl;
                        m_handleSelected = MIDDLEHANDLE;
                    }
                }
            }
        }
    }
}

void KisToolPerspectiveTransform::move(KisMoveEvent *event)
{
    switch(m_interractionMode)
    {
        case DRAWRECTINTERRACTION:
        {
            if (m_dragging) {
            // erase old lines on canvas
                paintOutline();
            // get current mouse position
                m_dragEnd = event->pos();
            // draw new lines on canvas
                paintOutline();
            }
        }

        case EDITRECTINTERRACTION:
        {
            if(m_currentSelectedPoint)
            {
                paintOutline();
                KisPoint translate = event->pos() - m_dragEnd;
                m_dragEnd = event->pos();
                *m_currentSelectedPoint += translate;;
                paintOutline();
                m_actualyMoveWhileSelected = true;
            }
            else if(m_handleSelected == TOPHANDLE || m_handleSelected == LEFTHANDLE || m_handleSelected == BOTTOMHANDLE || m_handleSelected == RIGHTHANDLE)
            {
                paintOutline();

                KisPoint translate = event->pos() - m_dragEnd;
                m_dragEnd = event->pos();

                double matrixFrom[3][3];
                double* b = KisPerspectiveMath::computeMatrixTransfoToPerspective(m_topleft, m_topright, m_bottomleft, m_bottomright, m_initialRect);
                for(int i = 0; i < 3; i++)
                {
                    for(int j = 0; j < 3; j++)
                    {
                        matrixFrom[i][j] = b[3*i+j];
                    }
                }
                delete b;

                KisPoint topLeft = KisPerspectiveMath::matProd(matrixFrom, KisPoint(m_initialRect.topLeft()) );
                KisPoint topRight = KisPerspectiveMath::matProd(matrixFrom, KisPoint(m_initialRect.topRight()) );
                KisPoint bottomLeft = KisPerspectiveMath::matProd(matrixFrom, KisPoint(m_initialRect.bottomLeft()) );
                KisPoint bottomRight = KisPerspectiveMath::matProd(matrixFrom, KisPoint(m_initialRect.bottomRight()) );
                TQRect dstRect = m_initialRect;
                switch(m_handleSelected)
                {
                    case TOPHANDLE:
                        dstRect.setTop(  static_cast<int>( dstRect.top() + translate.y() ) ) ;
                        break;
                    case LEFTHANDLE:
                        dstRect.setLeft(  static_cast<int>( dstRect.left() + translate.x() ) );
                        break;
                    case BOTTOMHANDLE:
                        dstRect.setBottom(  static_cast<int>( dstRect.bottom() + translate.y() ) );
                        break;
                    case RIGHTHANDLE:
                        dstRect.setRight(  static_cast<int>( dstRect.right() + translate.x() ) );
                        break;
                    case MIDDLEHANDLE:
                    case NOHANDLE:
                        kdDebug() << "Should NOT happen" << endl;
                }
                double matrixTo[3][3];
                b = KisPerspectiveMath::computeMatrixTransfoToPerspective(topLeft, topRight, bottomLeft, bottomRight, dstRect );
                for(int i = 0; i < 3; i++)
                {
                    for(int j = 0; j < 3; j++)
                    {
                        matrixTo[i][j] = b[3*i+j];
                    }
                }
                delete b;
                m_topleft = KisPerspectiveMath::matProd(matrixTo, KisPoint(m_initialRect.topLeft()));
                m_topright = KisPerspectiveMath::matProd(matrixTo, KisPoint(m_initialRect.topRight()));
                m_bottomleft = KisPerspectiveMath::matProd(matrixTo, KisPoint(m_initialRect.bottomLeft()));
                m_bottomright = KisPerspectiveMath::matProd(matrixTo, KisPoint(m_initialRect.bottomRight()));

                paintOutline();
                m_actualyMoveWhileSelected = true;
            } else if (m_handleSelected == MIDDLEHANDLE) {
                paintOutline();
                KisPoint translate = event->pos() - m_dragEnd;
                m_dragEnd = event->pos();
                m_topleft += translate;
                m_topright += translate;
                m_bottomleft += translate;
                m_bottomright += translate;
                paintOutline();
                m_actualyMoveWhileSelected = true;
            }
        }
    };
}

void KisToolPerspectiveTransform::buttonRelease(KisButtonReleaseEvent * event)
{
    KisImageSP img = m_subject->currentImg();

    if (!img)
        return;
    if( event->button() == TQt::LeftButton)
    {
        switch(m_interractionMode)
        {
            case DRAWRECTINTERRACTION:
            {
                 if (m_dragging && event->button() == TQt::LeftButton)  {
                    paintOutline();
                    m_dragging = false;
                    m_points.append (m_dragEnd);
                    if( m_points.size() == 4)
                    {
                        // from the points, select which is topleft ? topright ? bottomright ? and bottomleft ?
                        m_topleft = m_points[0];
                        m_topright  = m_points[1];
                        m_bottomleft  = m_points[3];
                        m_bottomright  = m_points[2];
                        double matrix[3][3];
                        double* b = KisPerspectiveMath::computeMatrixTransfoToPerspective(m_topleft, m_topright, m_bottomleft, m_bottomright, m_initialRect );
                        for(int i = 0; i < 3; i++)
                        {
                            for(int j = 0; j < 3; j++)
                            {
                                kdDebug() << "sol[" << 3*i+j << "]=" << b[3*i+j] << endl;
                                matrix[i][j] = b[3*i+j];
                            }
                        }
                        m_topleft = KisPerspectiveMath::matProd(matrix, KisPoint(m_initialRect.topLeft()));
                        m_topright = KisPerspectiveMath::matProd(matrix, KisPoint(m_initialRect.topRight()));
                        m_bottomleft = KisPerspectiveMath::matProd(matrix, KisPoint(m_initialRect.bottomLeft()));
                        m_bottomright = KisPerspectiveMath::matProd(matrix, KisPoint(m_initialRect.bottomRight()));
                        m_interractionMode = EDITRECTINTERRACTION;
                        paintOutline();
                        TQApplication::setOverrideCursor(KisCursor::waitCursor());
                        transform();
                        TQApplication::restoreOverrideCursor();
                    } else {
                        paintOutline();
                    }
                }
            }
            break;
            case EDITRECTINTERRACTION:
            {
                if(m_currentSelectedPoint )
                {
                    m_currentSelectedPoint = 0;
                    if(m_actualyMoveWhileSelected)
                    {
                        paintOutline();
                        TQApplication::setOverrideCursor(KisCursor::waitCursor());
                        transform();
                        TQApplication::restoreOverrideCursor();
                    }
                }
                if(m_handleSelected != NOHANDLE)
                {
                    m_handleSelected = NOHANDLE;
                    if(m_actualyMoveWhileSelected)
                    {
//                         paintOutline();
                        TQApplication::setOverrideCursor(KisCursor::waitCursor());
                        transform();
                        TQApplication::restoreOverrideCursor();
                    }
                }
            }
            break;
        }
    }
}

void KisToolPerspectiveTransform::paintOutline()
{
    if (m_subject) {
        KisCanvasController *controller = m_subject->canvasController();
        KisCanvas *canvas = controller->kiscanvas();
        KisCanvasPainter gc(canvas);
        TQRect rc;

        paintOutline(gc, rc);
    }
}

void KisToolPerspectiveTransform::paintOutline(KisCanvasPainter& gc, const TQRect&)
{
    if (m_subject) {
        KisCanvasController *controller = m_subject->canvasController();
        RasterOp op = gc.rasterOp();
        TQPen old = gc.pen();
        TQPen pen(TQt::SolidLine);
        pen.setWidth(1);
        Q_ASSERT(controller);

        switch(m_interractionMode)
        {
            case DRAWRECTINTERRACTION:
            {
                kdDebug() << "DRAWRECTINTERRACTION paintOutline " << m_points.size() << endl;
                KisPoint start, end;
                TQPoint startPos;
                TQPoint endPos;
                for (KisPointVector::iterator it = m_points.begin(); it != m_points.end(); ++it) {

                    if (it == m_points.begin())
                    {
                        start = (*it);
                    } else {
                        end = (*it);

                        startPos = controller->windowToView(start.floorTQPoint());
                        endPos = controller->windowToView(end.floorTQPoint());

                        gc.drawLine(startPos, endPos);

                        start = end;
                    }
                }
            }
            break;
            case EDITRECTINTERRACTION:
            {
                TQPoint topleft = controller->windowToView(m_topleft ).roundTQPoint();
                TQPoint topright = controller->windowToView(m_topright).roundTQPoint();
                TQPoint bottomleft = controller->windowToView(m_bottomleft).roundTQPoint();
                TQPoint bottomright = controller->windowToView(m_bottomright).roundTQPoint();

                gc.setRasterOp(TQt::NotROP);
                gc.setPen(pen);
                gc.drawRect(topleft.x()-4, topleft.y()-4, 8, 8);
                gc.drawLine(topleft.x(), topleft.y(), (topleft.x()+topright.x())/2, (topleft.y()+topright.y())/2);
                gc.drawRect((topleft.x()+topright.x())/2-4, (topleft.y()+topright.y())/2-4, 8, 8);
                gc.drawLine((topleft.x()+topright.x())/2, (topleft.y()+topright.y())/2, topright.x(), topright.y());
                gc.drawRect(topright.x()-4, topright.y()-4, 8, 8);
                gc.drawLine(topright.x(), topright.y(), (topright.x()+bottomright.x())/2, (topright.y()+bottomright.y())/2);
                gc.drawRect((topright.x()+bottomright.x())/2-4, (topright.y()+bottomright.y())/2-4, 8, 8);
                gc.drawLine((topright.x()+bottomright.x())/2, (topright.y()+bottomright.y())/2,bottomright.x(), bottomright.y());
                gc.drawRect(bottomright.x()-4, bottomright.y()-4, 8, 8);
                gc.drawLine(bottomright.x(), bottomright.y(), (bottomleft.x()+bottomright.x())/2, (bottomleft.y()+bottomright.y())/2);
                gc.drawRect((bottomleft.x()+bottomright.x())/2-4, (bottomleft.y()+bottomright.y())/2-4, 8, 8);
                gc.drawLine((bottomleft.x()+bottomright.x())/2, (bottomleft.y()+bottomright.y())/2, bottomleft.x(), bottomleft.y());
                gc.drawRect(bottomleft.x()-4, bottomleft.y()-4, 8, 8);
                gc.drawLine(bottomleft.x(), bottomleft.y(), (topleft.x()+bottomleft.x())/2, (topleft.y()+bottomleft.y())/2);
                gc.drawRect((topleft.x()+bottomleft.x())/2-4, (topleft.y()+bottomleft.y())/2-4, 8, 8);
                gc.drawLine((topleft.x()+bottomleft.x())/2, (topleft.y()+bottomleft.y())/2, topleft.x(), topleft.y());
                gc.drawRect((bottomleft.x()+bottomright.x()+topleft.x()+topright.x())/4-4, (bottomleft.y()+bottomright.y()+topleft.y()+topright.y())/4-4, 8, 8);
            }
            break;
        }
        gc.setRasterOp(op);
        gc.setPen(old);
    }
}

void KisToolPerspectiveTransform::transform()
{
    KisImageSP img = m_subject->currentImg();

    if (!img || !img->activeDevice())
        return;

    KisProgressDisplayInterface *progress = m_subject->progressDisplay();

    // This mementoes the current state of the active device.
    PerspectiveTransformCmd * transaction = new PerspectiveTransformCmd(this, img->activeDevice(), m_origDevice,
            m_topleft, m_topright, m_bottomleft, m_bottomright, m_origSelection, m_initialRect);

    // Copy the original state back.
    TQRect rc = m_origDevice->extent();
    rc = rc.normalize();
    img->activeDevice()->clear();
    KisPainter gc(img->activeDevice());
    gc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, m_origDevice, rc.x(), rc.y(), rc.width(), rc.height());
    gc.end();

    // Also restore the original selection.
    if(m_origSelection)
    {
        TQRect rc = m_origSelection->selectedRect();
        rc = rc.normalize();
        img->activeDevice()->selection()->clear();
        KisPainter sgc(img->activeDevice()->selection().data());
        sgc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, m_origSelection.data(), rc.x(), rc.y(), rc.width(), rc.height());
        sgc.end();
    }
    else
        if(img->activeDevice()->hasSelection())
            img->activeDevice()->selection()->clear();

    // Perform the transform. Since we copied the original state back, this doesn't degrade
    // after many tweaks. Since we started the transaction before the copy back, the memento
    // has the previous state.
    KisPerspectiveTransformWorker t(img->activeDevice(),m_topleft, m_topright, m_bottomleft, m_bottomright, progress);
    t.run();

    // If canceled, go back to the memento
    if(t.isCanceled())
    {
        transaction->unexecute();
        delete transaction;
        return;
    }

    img->activeDevice()->setDirty(rc); // XXX: This is not enough - should union with new extent

    // Else add the command -- this will have the memento from the previous state,
    // and the transformed state from the original device we cached in our activated()
    // method.
    if (transaction) {
        if (img->undo())
            img->undoAdapter()->addCommand(transaction);
        else
            delete transaction;
    }
}

void KisToolPerspectiveTransform::notifyCommandAdded( KCommand * command)
{
    PerspectiveTransformCmd * cmd = dynamic_cast<PerspectiveTransformCmd*>(command);
    if (cmd == 0) {
        // The last added command wasn't one of ours;
        // we should reset to the new state of the canvas.
        // In effect we should treat this as if the tool has been just activated
        initHandles();
    }
}

void KisToolPerspectiveTransform::notifyCommandExecuted( KCommand * command)
{
    Q_UNUSED(command);
    PerspectiveTransformCmd * cmd=0;
    if(m_subject->currentImg()->undoAdapter()->presentCommand())
        cmd = dynamic_cast<PerspectiveTransformCmd*>(m_subject->currentImg()->undoAdapter()->presentCommand());

    if (cmd == 0) {
        // The command now on the top of the stack isn't one of ours
        // We should treat this as if the tool has been just activated
        initHandles();
    }
    else
    {
        // One of our commands is now on top
        // We should ask for tool args and orig selection
        m_origDevice = cmd->origDevice();
        cmd->transformArgs(m_topleft, m_topright, m_bottomleft, m_bottomright);
        m_origSelection = cmd->origSelection(m_initialRect);
        m_subject->canvasController() ->updateCanvas();
    }
}

void KisToolPerspectiveTransform::slotLayerActivated(KisLayerSP)
{
    activate();
}


TQWidget* KisToolPerspectiveTransform::createOptionWidget(TQWidget* /*parent*/)
{
#if 0
    m_optWidget = new WdgToolPerspectiveTransform(parent);
    TQ_CHECK_PTR(m_optWidget);

    m_optWidget->cmbFilter->clear();
    m_optWidget->cmbFilter->setIDList(KisFilterStrategyRegistry::instance()->listKeys());

    m_optWidget->cmbFilter->setCurrentText("Mitchell");
    connect(m_optWidget->cmbFilter, TQ_SIGNAL(activated(const KisID &)),
        this, TQ_SLOT(slotSetFilter(const KisID &)));

    KisID filterID = m_optWidget->cmbFilter->currentItem();
    m_filter = KisFilterStrategyRegistry::instance()->get(filterID);

/*
    connect(m_optWidget->intStartX, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(setStartX(int)));
    connect(m_optWidget->intStartY, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(setStartY(int)));
    connect(m_optWidget->intEndX, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(setEndX(int)));
    connect(m_optWidget->intEndY, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(setEndY(int)));
*/
    m_optWidget->intStartX->hide();
    m_optWidget->intStartY->hide();
    m_optWidget->intEndX->hide();
    m_optWidget->intEndY->hide();
    m_optWidget->textLabel1->hide();
    m_optWidget->textLabel2->hide();
    m_optWidget->textLabel3->hide();
    m_optWidget->textLabel4->hide();
#endif
    return 0;
}

TQWidget* KisToolPerspectiveTransform::optionWidget()
{
    return 0;
}

void KisToolPerspectiveTransform::setup(TDEActionCollection *collection)
{
    m_action = static_cast<TDERadioAction *>(collection->action(name()));

    if (m_action == 0) {
        m_action = new TDERadioAction(i18n("&Perspective Transform"),
                        "tool_perspectivetransform",
                        0,
                        this,
                        TQ_SLOT(activate()),
                        collection,
                        name());
        TQ_CHECK_PTR(m_action);
        m_action->setToolTip(i18n("Perspective transform a layer or a selection"));
        m_action->setExclusiveGroup("tools");
        m_ownAction = true;
    }
}

#include "kis_tool_perspectivetransform.moc"
