/***************************************************************************
 *   Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
 *                                                                         *
 *   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 of the License, 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.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>  *
 ***************************************************************************/
/** @file
 * A Graphic view with more functionalities.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skggraphicsview.h"

#include <KMenu>
#include <KFileDialog>

#include <QDesktopServices>
#include <QPrinter>
#include <QPrintDialog>
#include <QClipboard>
#include <QApplication>
#include <QDomDocument>
#include <QSvgGenerator>
#include <QGraphicsSceneWheelEvent>
#include <qmath.h>

#include "skgservices.h"
#include "skgtraces.h"
#include "skgmainpanel.h"

SKGGraphicsView::SKGGraphicsView(QWidget* iParent)
    : QWidget(iParent), m_oscale(1), m_toolBarVisible(true)
{
    ui.setupUi(this);
    setAntialiasing(true);

    /*ui.kGraphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    ui.kGraphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);*/

    graphicsView()->installEventFilter(this);

    // Set icons
    ui.kPrint->setIcon(KIcon("printer"));
    ui.kCopy->setIcon(KIcon("edit-copy"));

    // Build contextual menu
    graphicsView()->setContextMenuPolicy(Qt::CustomContextMenu);

    m_mainMenu = new KMenu(graphicsView());

    // Zoom in menu
    SKGZoomSelector* zoomMenu = new SKGZoomSelector();
    zoomMenu->setResetValue(ui.kZoom->resetValue());
    zoomMenu->setValue(ui.kZoom->value());

    QWidgetAction* zoomWidget = new QWidgetAction(this);
    zoomWidget->setDefaultWidget(zoomMenu);
    m_mainMenu->addAction(zoomWidget);

    connect(zoomMenu, SIGNAL(changed(int)), ui.kZoom, SLOT(setValue(int)));
    connect(ui.kZoom, SIGNAL(changed(int)), zoomMenu, SLOT(setValue(int)));

    m_actShowToolBar = m_mainMenu->addAction(KIcon("show-menu"), i18nc("Noun, user action", "Show tool bar"));
    if (m_actShowToolBar) {
        m_actShowToolBar->setCheckable(true);
        m_actShowToolBar->setChecked(true);
        connect(m_actShowToolBar, SIGNAL(triggered(bool)), this, SLOT(onSwitchToolBarVisibility()));
    }

    m_mainMenu->addSeparator();

    QAction* actCopy = m_mainMenu->addAction(ui.kCopy->icon(), ui.kCopy->toolTip());
    connect(actCopy, SIGNAL(triggered(bool)), this, SLOT(onCopy()));

    QAction* actPrint = m_mainMenu->addAction(ui.kPrint->icon(), ui.kPrint->toolTip());
    connect(actPrint, SIGNAL(triggered(bool)), this, SLOT(onPrint()));

    QAction* actExport = m_mainMenu->addAction(KIcon("document-export"), i18nc("Noun, user action", "Export..."));
    connect(actExport, SIGNAL(triggered(bool)), this, SLOT(onExport()));

    connect(graphicsView(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));

    // Timer to refresh
    m_timer.setSingleShot(true);
    connect(&m_timer, SIGNAL(timeout()), ui.kZoom, SLOT(initializeZoom()), Qt::QueuedConnection);
}

SKGGraphicsView::~SKGGraphicsView()
{
    m_actShowToolBar = NULL;
    m_actZoomOriginal = NULL;
    m_mainMenu = NULL;
    m_actAntialiasing = NULL;
    m_actZoomOriginal = NULL;
    m_actAntialiasing = NULL;
}

void SKGGraphicsView::setScene(QGraphicsScene* iScene)
{
    graphicsView()->setScene(iScene);
    if (iScene) {
        iScene->installEventFilter(this);
    }
    onZoom();
}

QGraphicsView* SKGGraphicsView::graphicsView()
{
    return ui.kGraphicsView;
}

QString SKGGraphicsView::getState() const
{
    SKGTRACEINFUNC(10);
    QDomDocument doc("SKGML");
    QDomElement root = doc.createElement("parameters");
    doc.appendChild(root);

    root.setAttribute("isToolBarVisible", isToolBarVisible() ? "Y" : "N");

    return doc.toString();
}

void SKGGraphicsView::setState(const QString& iState)
{
    SKGTRACEINFUNC(10);
    QDomDocument doc("SKGML");
    doc.setContent(iState);
    QDomElement root = doc.documentElement();
    setToolBarVisible(root.attribute("isToolBarVisible") != "N");
}

KMenu* SKGGraphicsView::getContextualMenu() const
{
    return m_mainMenu;
}

void SKGGraphicsView::showMenu(const QPoint& iPos)
{
    if (m_mainMenu) {
        m_mainMenu->popup(graphicsView()->mapToGlobal(iPos));
    }
}

void SKGGraphicsView::setToolBarVisible(bool iVisibility)
{
    m_toolBarVisible = iVisibility;
    ui.toolBar->setVisible(m_toolBarVisible);
    if (m_actShowToolBar) {
        m_actShowToolBar->setChecked(m_toolBarVisible);
    }
}

bool SKGGraphicsView::isToolBarVisible() const
{
    return m_toolBarVisible;
}

void SKGGraphicsView::addToolbarWidget(QWidget* iWidget)
{
    ui.layout->insertWidget(3, iWidget);
}

void SKGGraphicsView::onSwitchToolBarVisibility()
{
    setToolBarVisible(!isToolBarVisible());
}

void SKGGraphicsView::setAntialiasing(bool iAntialiasing)
{
    graphicsView()->setRenderHint(QPainter::Antialiasing, iAntialiasing);
}

bool SKGGraphicsView::eventFilter(QObject* iObject, QEvent* iEvent)
{
    if (iObject == graphicsView()->scene() &&  iEvent && iEvent->type() == QEvent::GraphicsSceneWheel) {
        QGraphicsSceneWheelEvent* e = static_cast<QGraphicsSceneWheelEvent*>(iEvent);
        if (e && e->orientation() == Qt::Vertical && QApplication::keyboardModifiers() &Qt::ControlModifier) {
            int numDegrees = e->delta() / 8;
            int numTicks = numDegrees / 15;

            if (numTicks > 0) {
                ui.kZoom->zoomIn();
            } else {
                ui.kZoom->zoomOut();
            }
            e->setAccepted(true);
            return true;
        }
    } else if (iObject == graphicsView() &&  iEvent && iEvent->type() == QEvent::Resize) {
        Q_EMIT resized();
        if (ui.kZoom->value() == ui.kZoom->resetValue()) {
            m_timer.start(300);
        }
    }
    return QWidget::eventFilter(iObject, iEvent);
}

void SKGGraphicsView::initializeZoom()
{
    ui.kZoom->initializeZoom();
}

void SKGGraphicsView::onZoom()
{
    _SKGTRACEINFUNC(10);
    int sliderValue = ui.kZoom->value();
    if (graphicsView()->scene()) {
        if (sliderValue == -10) {
            graphicsView()->fitInView(graphicsView()->scene()->sceneRect(), Qt::KeepAspectRatio);
            m_oscale = 1;
        } else {
            qreal scale = qPow(qreal(1.5), (sliderValue + 10.0) / qreal(4));
            graphicsView()->scale(scale / m_oscale, scale / m_oscale);
            m_oscale = scale;
        }
    }
}

void SKGGraphicsView::onPrint()
{
    _SKGTRACEINFUNC(10);
    QPrinter printer;
    QPointer<QPrintDialog> dialog = new QPrintDialog(&printer, this);
    if (dialog->exec() == QDialog::Accepted) {
        QPainter painter(&printer);
        graphicsView()->render(&painter);
        painter.end();
    }
    delete dialog;
}

void SKGGraphicsView::onExport()
{
    _SKGTRACEINFUNC(10);
    QString fileName = SKGMainPanel::getSaveFileName("kfiledialog:///IMPEXP", "application/pdf image/svg+xml image/png image/jpeg image/gif image/tiff", this);
    if (fileName.isEmpty()) {
        return;
    }

    exportInFile(fileName);

    QDesktopServices::openUrl(QUrl(fileName));
}

void SKGGraphicsView::exportInFile(const QString& iFileName)
{
    _SKGTRACEINFUNC(10);
    QString extension = QFileInfo(iFileName).suffix().toUpper();
    if (extension == "PDF") {
        QPrinter printer;
        printer.setOutputFileName(iFileName);
        QPainter painter(&printer);
        graphicsView()->render(&painter);
        painter.end();
    } else if (extension == "SVG") {
        QSvgGenerator generator;
        generator.setFileName(iFileName);
        generator.setSize(QSize(200, 200));
        generator.setViewBox(QRect(0, 0, 200, 200));
        generator.setTitle(i18nc("Title of the content SVG export", "Skrooge SVG export"));
        generator.setDescription(i18nc("Description of the content SVG export", "A SVG drawing created by the Skrooge."));

        QPainter painter(&generator);
        graphicsView()->render(&painter);
        painter.end();
    } else {
        QImage image(graphicsView()->size(), QImage::Format_ARGB32);
        QPainter painter(&image);
        graphicsView()->render(&painter);
        painter.end();
        image.save(iFileName);
    }
}

void SKGGraphicsView::onCopy()
{
    _SKGTRACEINFUNC(10);
    QClipboard* clipboard = QApplication::clipboard();
    if (clipboard) {
        QImage image(graphicsView()->size(), QImage::Format_ARGB32);
        QPainter painter(&image);
        graphicsView()->render(&painter);
        painter.end();
        clipboard->setImage(image);
    }
}
#include "skggraphicsview.moc"

