/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2007-03-05
 * Description : a widget to display 2 preview image on 
 *               lightable to compare pictures.
 *
 * Copyright (C) 2007-2008 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.
 *
 * ============================================================ */

// TQt includes.

#include <tqlayout.h>

// KDE includes.

#include <kdialogbase.h>

// Local includes.

#include "ddebug.h"
#include "thumbnailsize.h"
#include "lighttablepreview.h"
#include "lighttableview.h"
#include "lighttableview.moc"

namespace Digikam
{

class LightTableViewPriv
{
public:

    LightTableViewPriv()
    {
        syncPreview  = false;
        leftLoading  = false;
        rightLoading = false;
        leftPreview  = 0;
        rightPreview = 0;
        grid         = 0;
    }

    bool               syncPreview;
    bool               leftLoading;     // To not sync right panel during left loading.
    bool               rightLoading;    // To not sync left panel during right loading.

    TQGridLayout       *grid;

    LightTablePreview *leftPreview;
    LightTablePreview *rightPreview;
};

LightTableView::LightTableView(TQWidget *parent)
              : TQFrame(parent, 0, TQt::WDestructiveClose)
{
    d = new LightTableViewPriv;

    setFrameStyle(TQFrame::NoFrame);
    setMargin(0);
    setLineWidth(0);

    d->grid         = new TQGridLayout(this, 1, 1, 0, 1);
    d->leftPreview  = new LightTablePreview(this);
    d->rightPreview = new LightTablePreview(this);

    d->grid->addMultiCellWidget(d->leftPreview,  0, 0, 0, 0);
    d->grid->addMultiCellWidget(d->rightPreview, 0, 0, 1, 1);

    d->grid->setColStretch(0, 10),
    d->grid->setColStretch(1, 10),
    d->grid->setRowStretch(0, 10),

    // Left panel connections ------------------------------------------------

    connect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
            this, TQ_SIGNAL(signalLeftZoomFactorChanged(double)));

    connect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)),
            this, TQ_SLOT(slotLeftContentsMoved(int, int)));

    connect(d->leftPreview, TQ_SIGNAL(signalSlideShow()),
            this, TQ_SIGNAL(signalSlideShow()));

    connect(d->leftPreview, TQ_SIGNAL(signalDeleteItem(ImageInfo*)),
            this, TQ_SIGNAL(signalDeleteItem(ImageInfo*)));

    connect(d->leftPreview, TQ_SIGNAL(signalEditItem(ImageInfo*)),
            this, TQ_SIGNAL(signalEditItem(ImageInfo*)));

    connect(d->leftPreview, TQ_SIGNAL(signalDroppedItems(const ImageInfoList&)),
            this, TQ_SIGNAL(signalLeftDroppedItems(const ImageInfoList&)));

    connect(d->leftPreview, TQ_SIGNAL(signalPreviewLoaded(bool)),
            this, TQ_SLOT(slotLeftPreviewLoaded(bool)));

    connect(d->leftPreview, TQ_SIGNAL(signalLeftButtonClicked()),
            this, TQ_SIGNAL(signalLeftPanelLeftButtonClicked()));

    // Right panel connections ------------------------------------------------
    
    connect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
            this, TQ_SIGNAL(signalRightZoomFactorChanged(double)));

    connect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)),
            this, TQ_SLOT(slotRightContentsMoved(int, int)));
    
    connect(d->rightPreview, TQ_SIGNAL(signalDeleteItem(ImageInfo*)),
            this, TQ_SIGNAL(signalDeleteItem(ImageInfo*)));
    
    connect(d->rightPreview, TQ_SIGNAL(signalEditItem(ImageInfo*)),
            this, TQ_SIGNAL(signalEditItem(ImageInfo*)));

    connect(d->rightPreview, TQ_SIGNAL(signalDroppedItems(const ImageInfoList&)),
            this, TQ_SIGNAL(signalRightDroppedItems(const ImageInfoList&)));

    connect(d->rightPreview, TQ_SIGNAL(signalSlideShow()),
            this, TQ_SIGNAL(signalSlideShow()));

    connect(d->rightPreview, TQ_SIGNAL(signalPreviewLoaded(bool)),
            this, TQ_SLOT(slotRightPreviewLoaded(bool)));

    connect(d->rightPreview, TQ_SIGNAL(signalLeftButtonClicked()),
            this, TQ_SIGNAL(signalRightPanelLeftButtonClicked()));
}

LightTableView::~LightTableView()
{
    delete d;
}

void LightTableView::setLoadFullImageSize(bool b)
{
    d->leftPreview->setLoadFullImageSize(b); 
    d->rightPreview->setLoadFullImageSize(b); 
}

void LightTableView::setSyncPreview(bool sync)
{
    d->syncPreview = sync;

    // Left panel like a reference to resync preview.
    if (d->syncPreview)    
        slotLeftContentsMoved(d->leftPreview->contentsX(), d->leftPreview->contentsY());
}

void LightTableView::setNavigateByPair(bool b)
{
    d->leftPreview->setDragAndDropEnabled(!b); 
    d->rightPreview->setDragAndDropEnabled(!b); 
}

void LightTableView::slotDecreaseZoom()
{
    if (d->syncPreview)
    {
        slotDecreaseLeftZoom();
        return;
    }

    if (d->leftPreview->isSelected())
        slotDecreaseLeftZoom();
    else if (d->rightPreview->isSelected())
        slotDecreaseRightZoom();
}   

void LightTableView::slotIncreaseZoom()
{
    if (d->syncPreview)
    { 
        slotIncreaseLeftZoom();
        return;
    }

    if (d->leftPreview->isSelected())
        slotIncreaseLeftZoom();
    else if (d->rightPreview->isSelected())
        slotIncreaseRightZoom();
}   

void LightTableView::slotDecreaseLeftZoom()
{
    d->leftPreview->slotDecreaseZoom(); 
}   

void LightTableView::slotIncreaseLeftZoom()
{
    d->leftPreview->slotIncreaseZoom(); 
}   

void LightTableView::slotDecreaseRightZoom()
{
    d->rightPreview->slotDecreaseZoom(); 
}   

void LightTableView::slotIncreaseRightZoom()
{
    d->rightPreview->slotIncreaseZoom(); 
}   

void LightTableView::setLeftZoomFactor(double z)
{
    d->leftPreview->setZoomFactor(z); 
}

void LightTableView::setRightZoomFactor(double z)
{
    d->rightPreview->setZoomFactor(z); 
}

void LightTableView::fitToWindow()
{
    d->leftPreview->fitToWindow(); 
    d->rightPreview->fitToWindow(); 
}

void LightTableView::toggleFitToWindowOr100()
{
    //  If we are currently precisely at 100%, then fit to window,
    //  otherwise zoom to a centered 100% view.
    if ((d->leftPreview->zoomFactor()==1.0) && 
        (d->rightPreview->zoomFactor()==1.0)) 
    {
        fitToWindow();
    }
    else
    {
        d->leftPreview->setZoomFactor(1.0, true);
        d->rightPreview->setZoomFactor(1.0, true);
    }
}

double LightTableView::leftZoomMax()
{
    return d->leftPreview->zoomMax(); 
}

double LightTableView::leftZoomMin()
{
    return d->leftPreview->zoomMin(); 
}

bool LightTableView::leftMaxZoom()
{
    return d->leftPreview->maxZoom(); 
}

bool LightTableView::leftMinZoom()
{
    return d->leftPreview->minZoom(); 
}

double LightTableView::rightZoomMax()
{
    return d->rightPreview->zoomMax(); 
}

double LightTableView::rightZoomMin()
{
    return d->rightPreview->zoomMin(); 
}

bool LightTableView::rightMaxZoom()
{
    return d->rightPreview->maxZoom(); 
}

bool LightTableView::rightMinZoom()
{
    return d->rightPreview->minZoom(); 
}

void LightTableView::slotLeftZoomSliderChanged(int size)
{
    double h    = (double)ThumbnailSize::Huge;
    double s    = (double)ThumbnailSize::Small;
    double zmin = d->leftPreview->zoomMin();
    double zmax = d->leftPreview->zoomMax();
    double b    = (zmin-(zmax*s/h))/(1-s/h);
    double a    = (zmax-b)/h;
    double z    = a*size+b; 

    d->leftPreview->setZoomFactorSnapped(z);
}

void LightTableView::slotRightZoomSliderChanged(int size)
{
    double h    = (double)ThumbnailSize::Huge;
    double s    = (double)ThumbnailSize::Small;
    double zmin = d->rightPreview->zoomMin();
    double zmax = d->rightPreview->zoomMax();
    double b    = (zmin-(zmax*s/h))/(1-s/h);
    double a    = (zmax-b)/h;
    double z    = a*size+b; 

    d->rightPreview->setZoomFactorSnapped(z);
}

void LightTableView::leftReload()
{
    d->leftPreview->reload();
}

void LightTableView::rightReload()
{
    d->rightPreview->reload();
}

void LightTableView::slotLeftContentsMoved(int x, int y)
{
    if (d->syncPreview && !d->leftLoading)
    {
        disconnect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
                   this, TQ_SIGNAL(signalRightZoomFactorChanged(double)));
    
        disconnect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)),
                   this, TQ_SLOT(slotRightContentsMoved(int, int)));

        setRightZoomFactor(d->leftPreview->zoomFactor());
        emit signalRightZoomFactorChanged(d->leftPreview->zoomFactor());
        d->rightPreview->setContentsPos(x, y);

        connect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
                this, TQ_SIGNAL(signalRightZoomFactorChanged(double)));
    
        connect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)),
                this, TQ_SLOT(slotRightContentsMoved(int, int)));
    }
}

void LightTableView::slotRightContentsMoved(int x, int y)
{
    if (d->syncPreview && !d->rightLoading)
    {
        disconnect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
                   this, TQ_SIGNAL(signalLeftZoomFactorChanged(double)));
    
        disconnect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)),
                   this, TQ_SLOT(slotLeftContentsMoved(int, int)));


        setLeftZoomFactor(d->rightPreview->zoomFactor());
        emit signalLeftZoomFactorChanged(d->rightPreview->zoomFactor());
        d->leftPreview->setContentsPos(x, y);

        connect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
                this, TQ_SIGNAL(signalLeftZoomFactorChanged(double)));
    
        connect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)),
                this, TQ_SLOT(slotLeftContentsMoved(int, int)));
    }
}

ImageInfo* LightTableView::leftImageInfo() const
{
    return d->leftPreview->getImageInfo();
}

ImageInfo* LightTableView::rightImageInfo() const
{
    return d->rightPreview->getImageInfo();
}

void LightTableView::setLeftImageInfo(ImageInfo* info)
{
    d->leftLoading = true;
    d->leftPreview->setImageInfo(info);    
}

void LightTableView::setRightImageInfo(ImageInfo* info)
{
    d->rightLoading = true;
    d->rightPreview->setImageInfo(info);    
}

void LightTableView::slotLeftPreviewLoaded(bool success)
{
    checkForSyncPreview();
    d->leftLoading = false;
    slotRightContentsMoved(d->rightPreview->contentsX(), 
                           d->rightPreview->contentsY());

    emit signalLeftPreviewLoaded(success);
}

void LightTableView::slotRightPreviewLoaded(bool success)
{
    checkForSyncPreview();
    d->rightLoading = false;
    slotLeftContentsMoved(d->leftPreview->contentsX(), 
                          d->leftPreview->contentsY());

    emit signalRightPreviewLoaded(success);
}

void LightTableView::checkForSyncPreview()
{
    if (d->leftPreview->getImageInfo() && d->rightPreview->getImageInfo() &&
        d->leftPreview->getImageSize() == d->rightPreview->getImageSize())
    {
        d->syncPreview = true;
    }
    else
    {
        d->syncPreview = false;
    } 

    emit signalToggleOnSyncPreview(d->syncPreview); 
}

void LightTableView::checkForSelection(ImageInfo* info)
{
    if (!info)
    {
        d->leftPreview->setSelected(false);
        d->rightPreview->setSelected(false);
        return;
    }

    if (d->leftPreview->getImageInfo())
    {
        d->leftPreview->setSelected(d->leftPreview->getImageInfo()->id() == info->id());
    }

    if (d->rightPreview->getImageInfo())
    {
        d->rightPreview->setSelected(d->rightPreview->getImageInfo()->id() == info->id());
    }
}

}  // namespace Digikam

