/* This file is part of KGraphViewer.
   Copyright (C) 2005-2007 Gael de Chalendar <kleag@free.fr>

   KGraphViewer 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.

   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
*/

/* This file was part of the KDE project
   Copyright (C) 2005 Jarosław Staniek <staniek@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
 */

#include "KgvPageLayoutSize.h"

// lib
#include "KgvUnitWidgets.h"
#include "KgvPageLayoutDia.h"
#include "kgraphviewerlib_debug.h"
// KF
#include <KLocalizedString>
// Qt
#include <QGridLayout>
#include <QMessageBox>
#include <QGroupBox>
#include <QRadioButton>
#include <QLabel>

KgvPageLayoutSize::KgvPageLayoutSize(QWidget *parent, const KgvPageLayout &layout, KgvUnit::Unit unit, const KgvColumns &columns, bool unitChooser, bool enableBorders)
    : QWidget(parent)
    , m_blockSignals(false)
{
    m_layout = layout;
    m_unit = unit;

    QGridLayout *grid1 = new QGridLayout(this);
    if (unitChooser) {
        // ------------- unit _______________
        QWidget *unitFrame = new QWidget(this);
        grid1->addWidget(unitFrame, 0, 0, Qt::AlignLeft);
        QBoxLayout *unitLayout = new QHBoxLayout(unitFrame);

        // label unit
        QLabel *lpgUnit = new QLabel(i18n("Unit:"), unitFrame);
        unitLayout->addWidget(lpgUnit, 0, Qt::AlignRight | Qt::AlignVCenter);

        // combo unit
        QComboBox *cpgUnit = new QComboBox(unitFrame);
        lpgUnit->setBuddy(cpgUnit);
        cpgUnit->addItems(KgvUnit::listOfUnitName());
        cpgUnit->setCurrentIndex(unit);
        unitLayout->addWidget(cpgUnit, 0, Qt::AlignLeft | Qt::AlignVCenter);
        connect(cpgUnit, &QComboBox::activated, this, &KgvPageLayoutSize::setUnitInt);
    } else {
        QString str = KgvUnit::unitDescription(unit);

        QLabel *lpgUnit = new QLabel(i18n("All values are given in %1.", str), this);
        grid1->addWidget(lpgUnit, 0, 0, Qt::AlignLeft);
    }

    // -------------- page size -----------------
    QGroupBox *formatFrame = new QGroupBox(i18n("Page Size"), this);
    grid1->addWidget(formatFrame, 1, 0);
    QVBoxLayout *vlay = new QVBoxLayout;

    QWidget *formatPageSize = new QWidget(formatFrame);
    vlay->addWidget(formatPageSize);
    //     formatPageSize->setSpacing( KDialog::spacingHint() );

    // label page size
    QLabel *lpgFormat = new QLabel(i18n("&Size:"), formatPageSize);

    // combo size
    cpgFormat = new QComboBox(formatPageSize);
    cpgFormat->addItems(KgvPageFormat::allFormats());
    lpgFormat->setBuddy(cpgFormat);
    connect(cpgFormat, &QComboBox::activated, this, &KgvPageLayoutSize::formatChanged);
    QHBoxLayout *lay = new QHBoxLayout;
    lay->addWidget(lpgFormat);
    lay->addWidget(cpgFormat);
    formatPageSize->setLayout(lay);
    // spacer
    //     formatPageSize->setStretchFactor( new QWidget( formatPageSize ), 10 );

    QHBoxLayout *lay2 = new QHBoxLayout;
    QWidget *formatCustomSize = new QWidget(formatFrame);
    vlay->addWidget(formatCustomSize);
    formatFrame->setLayout(vlay);
    //     formatCustomSize->setSpacing( KDialog::spacingHint() );

    // label width
    QLabel *lpgWidth = new QLabel(i18n("&Width:"), formatCustomSize);
    lay2->addWidget(lpgWidth);
    // linedit width
    epgWidth = new KgvUnitDoubleSpinBox(formatCustomSize);
    lay2->addWidget(epgWidth);
    lpgWidth->setBuddy(epgWidth);
    if (m_layout.format != PG_CUSTOM)
        epgWidth->setEnabled(false);
    connect(epgWidth, &KgvUnitDoubleSpinBox::valueChangedPt, this, &KgvPageLayoutSize::widthChanged);

    // label height
    QLabel *lpgHeight = new QLabel(i18n("&Height:"), formatCustomSize);
    lay2->addWidget(lpgHeight);

    // linedit height
    epgHeight = new KgvUnitDoubleSpinBox(formatCustomSize);
    lay2->addWidget(epgHeight);
    lpgHeight->setBuddy(epgHeight);
    if (m_layout.format != PG_CUSTOM)
        epgHeight->setEnabled(false);
    connect(epgHeight, &KgvUnitDoubleSpinBox::valueChangedPt, this, &KgvPageLayoutSize::heightChanged);
    formatCustomSize->setLayout(lay2);

    // --------------- orientation ---------------
    QHBoxLayout *lay3 = new QHBoxLayout;
    m_orientGroup = new QGroupBox(i18n("Orientation"), this);
    //     m_orientGroup->setInsideSpacing( KDialog::spacingHint() );
    grid1->addWidget(m_orientGroup, 2, 0);

    QRadioButton *rbPortrait = new QRadioButton(i18n("&Portrait"), m_orientGroup);
    lay3->addWidget(rbPortrait);
    m_orientButtons.addButton(rbPortrait);

    QRadioButton *rbLandscape = new QRadioButton(i18n("La&ndscape"), m_orientGroup);
    lay3->addWidget(rbLandscape);
    m_orientGroup->setLayout(lay3);
    m_orientButtons.addButton(rbLandscape);

    connect(&m_orientButtons, &QButtonGroup::idClicked, this, &KgvPageLayoutSize::orientationChanged);

    // --------------- page margins ---------------
    QGroupBox *marginsFrame = new QGroupBox(i18n("Margins"), this);
    //     marginsFrame->setColumnLayout( 0, Qt::Vertical );
    //     marginsFrame->setMargin( KDialog::marginHint() );
    grid1->addWidget(marginsFrame, 3, 0);

    QWidget *marginsWidget = new QWidget(marginsFrame);
    QGridLayout *marginsLayout = new QGridLayout(marginsFrame);

    // left margin
    ebrLeft = new KgvUnitDoubleSpinBox(marginsWidget);
    marginsLayout->addWidget(ebrLeft, 1, 0);
    connect(ebrLeft, &KgvUnitDoubleSpinBox::valueChangedPt, this, &KgvPageLayoutSize::leftChanged);

    // right margin
    ebrRight = new KgvUnitDoubleSpinBox(marginsWidget);
    marginsLayout->addWidget(ebrRight, 1, 2);
    connect(ebrRight, &KgvUnitDoubleSpinBox::valueChangedPt, this, &KgvPageLayoutSize::rightChanged);

    // top margin
    ebrTop = new KgvUnitDoubleSpinBox(marginsWidget);
    marginsLayout->addWidget(ebrTop, 0, 1, Qt::AlignCenter);
    connect(ebrTop, &KgvUnitDoubleSpinBox::valueChangedPt, this, &KgvPageLayoutSize::topChanged);

    // bottom margin
    ebrBottom = new KgvUnitDoubleSpinBox(marginsWidget);
    marginsLayout->addWidget(ebrBottom, 2, 1, Qt::AlignCenter);
    connect(ebrBottom, &KgvUnitDoubleSpinBox::valueChangedPt, this, &KgvPageLayoutSize::bottomChanged);

    marginsFrame->setLayout(marginsLayout);

    // ------------- preview -----------
    pgPreview = new KgvPagePreview(this, "Preview", m_layout);
    grid1->addWidget(pgPreview, 1, 1, 3, 1);

    // ------------- spacers -----------
    QWidget *spacer1 = new QWidget(this);
    QWidget *spacer2 = new QWidget(this);
    spacer1->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
    spacer2->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
    grid1->addWidget(spacer1, 4, 0);
    grid1->addWidget(spacer2, 4, 1);

    setValues();
    updatePreview();
    pgPreview->setPageColumns(columns);
    setEnableBorders(enableBorders);
}

void KgvPageLayoutSize::setEnableBorders(bool on)
{
    m_haveBorders = on;
    ebrLeft->setEnabled(on);
    ebrRight->setEnabled(on);
    ebrTop->setEnabled(on);
    ebrBottom->setEnabled(on);

    // update m_layout
    m_layout.ptLeft = on ? ebrLeft->value() : 0;
    m_layout.ptRight = on ? ebrRight->value() : 0;
    m_layout.ptTop = on ? ebrTop->value() : 0;
    m_layout.ptBottom = on ? ebrBottom->value() : 0;

    // use updated m_layout
    updatePreview();
    Q_EMIT propertyChange(m_layout);
}

void KgvPageLayoutSize::updatePreview()
{
    pgPreview->setPageLayout(m_layout);
}

void KgvPageLayoutSize::setValues()
{
    // page format
    cpgFormat->setCurrentIndex(m_layout.format);
    // orientation
    //     m_orientGroup->setButton( m_layout.orientation == PG_PORTRAIT ? 0: 1 );

    setUnit(m_unit);
    updatePreview();
}

void KgvPageLayoutSize::setUnit(KgvUnit::Unit unit)
{
    m_unit = unit;
    m_blockSignals = true; // due to non-atomic changes the propertyChange emits should be blocked

    epgWidth->setUnit(m_unit);
    epgWidth->setMinMaxStep(0, KgvUnit::fromUserValue(9999, m_unit), KgvUnit::fromUserValue(0.01, m_unit));
    epgWidth->changeValue(m_layout.ptWidth);

    epgHeight->setUnit(m_unit);
    epgHeight->setMinMaxStep(0, KgvUnit::fromUserValue(9999, m_unit), KgvUnit::fromUserValue(0.01, m_unit));
    epgHeight->changeValue(m_layout.ptHeight);

    double dStep = KgvUnit::fromUserValue(0.2, m_unit);

    ebrLeft->setUnit(m_unit);
    ebrLeft->changeValue(m_layout.ptLeft);
    ebrLeft->setMinMaxStep(0, m_layout.ptWidth, dStep);

    ebrRight->setUnit(m_unit);
    ebrRight->changeValue(m_layout.ptRight);
    ebrRight->setMinMaxStep(0, m_layout.ptWidth, dStep);

    ebrTop->setUnit(m_unit);
    ebrTop->changeValue(m_layout.ptTop);
    ebrTop->setMinMaxStep(0, m_layout.ptHeight, dStep);

    ebrBottom->setUnit(m_unit);
    ebrBottom->changeValue(m_layout.ptBottom);
    ebrBottom->setMinMaxStep(0, m_layout.ptHeight, dStep);

    m_blockSignals = false;
}

void KgvPageLayoutSize::setUnitInt(int unit)
{
    setUnit((KgvUnit::Unit)unit);
}

void KgvPageLayoutSize::formatChanged(int format)
{
    if ((KgvFormat)format == m_layout.format)
        return;
    m_layout.format = (KgvFormat)format;
    bool enable = (KgvFormat)format == PG_CUSTOM;
    epgWidth->setEnabled(enable);
    epgHeight->setEnabled(enable);

    if (m_layout.format != PG_CUSTOM) {
        m_layout.ptWidth = MM_TO_POINT(KgvPageFormat::width(m_layout.format, m_layout.orientation));
        m_layout.ptHeight = MM_TO_POINT(KgvPageFormat::height(m_layout.format, m_layout.orientation));
    }

    epgWidth->changeValue(m_layout.ptWidth);
    epgHeight->changeValue(m_layout.ptHeight);

    updatePreview();
    Q_EMIT propertyChange(m_layout);
}

void KgvPageLayoutSize::orientationChanged(int which)
{
    qCDebug(KGRAPHVIEWERLIB_LOG) << "KgvPageLayoutSize::orientationChanged";
    m_layout.orientation = which == 0 ? PG_PORTRAIT : PG_LANDSCAPE;

    // swap dimension
    double val = epgWidth->value();
    epgWidth->changeValue(epgHeight->value());
    epgHeight->changeValue(val);
    // and adjust margins
    m_blockSignals = true;
    val = ebrTop->value();
    if (m_layout.orientation == PG_PORTRAIT) { // clockwise
        ebrTop->changeValue(ebrRight->value());
        ebrRight->changeValue(ebrBottom->value());
        ebrBottom->changeValue(ebrLeft->value());
        ebrLeft->changeValue(val);
    } else { // counter clockwise
        ebrTop->changeValue(ebrLeft->value());
        ebrLeft->changeValue(ebrBottom->value());
        ebrBottom->changeValue(ebrRight->value());
        ebrRight->changeValue(val);
    }
    m_blockSignals = false;

    setEnableBorders(m_haveBorders); // will update preview+emit
}

void KgvPageLayoutSize::widthChanged(double width)
{
    if (m_blockSignals)
        return;
    m_layout.ptWidth = width;
    updatePreview();
    Q_EMIT propertyChange(m_layout);
}
void KgvPageLayoutSize::heightChanged(double height)
{
    if (m_blockSignals)
        return;
    m_layout.ptHeight = height;
    updatePreview();
    Q_EMIT propertyChange(m_layout);
}
void KgvPageLayoutSize::leftChanged(double left)
{
    if (m_blockSignals)
        return;
    m_layout.ptLeft = left;
    updatePreview();
    Q_EMIT propertyChange(m_layout);
}
void KgvPageLayoutSize::rightChanged(double right)
{
    if (m_blockSignals)
        return;
    m_layout.ptRight = right;
    updatePreview();
    Q_EMIT propertyChange(m_layout);
}
void KgvPageLayoutSize::topChanged(double top)
{
    if (m_blockSignals)
        return;
    m_layout.ptTop = top;
    updatePreview();
    Q_EMIT propertyChange(m_layout);
}
void KgvPageLayoutSize::bottomChanged(double bottom)
{
    if (m_blockSignals)
        return;
    m_layout.ptBottom = bottom;
    updatePreview();
    Q_EMIT propertyChange(m_layout);
}

bool KgvPageLayoutSize::queryClose()
{
    if (m_layout.ptLeft + m_layout.ptRight > m_layout.ptWidth) {
        QMessageBox::critical(this, i18n("Page Layout Problem"), i18n("The page width is smaller than the left and right margins."));
        return false;
    }
    if (m_layout.ptTop + m_layout.ptBottom > m_layout.ptHeight) {
        QMessageBox::critical(this, i18n("Page Layout Problem"), i18n("The page height is smaller than the top and bottom margins."));
        return false;
    }
    return true;
}

void KgvPageLayoutSize::setColumns(KgvColumns &columns)
{
    pgPreview->setPageColumns(columns);
}

#include "moc_KgvPageLayoutSize.cpp"
