/* This file is part of the KDE project
 * Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
 * Copyright (C) 2005 Thomas Zander <zander@kde.org>
 *
 * This library 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; version 2.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <KoPageLayoutDia.h>
#include <KoPageLayoutSize.h>
#include <KoUnit.h>
#include <KoUnitWidgets.h>

#include <tdelocale.h>
#include <kiconloader.h>
#include <tdemessagebox.h>
#include <kdebug.h>

#include <tqlabel.h>
#include <tqlayout.h>
#include <tqradiobutton.h>
#include <tqhbox.h>
#include <tqvgroupbox.h>
#include <tqhbuttongroup.h>

KoPageLayoutSize::KoPageLayoutSize(TQWidget *parent, const KoPageLayout& layout, KoUnit::Unit unit,const KoColumns& columns,  bool unitChooser, bool enableBorders)
    : TQWidget(parent), m_blockSignals(false) {
    m_layout = layout;
    m_unit = unit;

    TQGridLayout *grid1 = new TQGridLayout( this, 5, 2, 0, KDialog::spacingHint() );
    if ( unitChooser ) {
        // ------------- unit _______________
        TQWidget* unitFrame = new TQWidget( this );
        grid1->addWidget( unitFrame, 0, 0, TQt::AlignLeft );
        TQBoxLayout* unitLayout = new TQHBoxLayout( unitFrame, 0, KDialog::spacingHint() );

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

        // combo unit
        TQComboBox *cpgUnit = new TQComboBox( false, unitFrame, "cpgUnit" );
        lpgUnit->setBuddy( cpgUnit );
        cpgUnit->insertStringList( KoUnit::listOfUnitName() );
        cpgUnit->setCurrentItem( unit );
        unitLayout->addWidget( cpgUnit, 0, TQt::AlignLeft | TQt::AlignVCenter );
        connect( cpgUnit, TQT_SIGNAL( activated( int ) ), this, TQT_SLOT( setUnitInt( int ) ) );
    }
    else {
        TQString str=KoUnit::unitDescription(unit);

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

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

    TQHBox *formatPageSize = new TQHBox( formatFrame );
    formatPageSize->setSpacing( KDialog::spacingHint() );

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

    // combo size
    cpgFormat = new TQComboBox( false, formatPageSize, "cpgFormat" );
    cpgFormat->insertStringList( KoPageFormat::allFormats() );
    lpgFormat->setBuddy( cpgFormat );
    connect( cpgFormat, TQT_SIGNAL( activated( int ) ), this, TQT_SLOT( formatChanged( int ) ) );

    // spacer
    formatPageSize->setStretchFactor( new TQWidget( formatPageSize ), 10 );

    TQHBox *formatCustomSize = new TQHBox( formatFrame );
    formatCustomSize->setSpacing( KDialog::spacingHint() );

    // label width
    TQLabel *lpgWidth = new TQLabel( i18n( "&Width:" ), formatCustomSize );

    // linedit width
    epgWidth = new KoUnitDoubleSpinBox( formatCustomSize, "Width" );
    lpgWidth->setBuddy( epgWidth );
    if ( m_layout.format != PG_CUSTOM )
        epgWidth->setEnabled( false );
    connect( epgWidth, TQT_SIGNAL( valueChangedPt(double) ), this, TQT_SLOT( widthChanged(double) ) );

    // label height
    TQLabel *lpgHeight = new TQLabel( i18n( "&Height:" ), formatCustomSize );

    // linedit height
    epgHeight = new KoUnitDoubleSpinBox( formatCustomSize, "Height" );
    lpgHeight->setBuddy( epgHeight );
    if ( m_layout.format != PG_CUSTOM )
        epgHeight->setEnabled( false );
    connect( epgHeight, TQT_SIGNAL( valueChangedPt(double ) ), this, TQT_SLOT( heightChanged(double) ) );

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

    TQLabel* lbPortrait = new TQLabel( m_orientGroup );
    lbPortrait->setPixmap( TQPixmap( UserIcon( "koPortrait" ) ) );
    lbPortrait->setMaximumWidth( lbPortrait->pixmap()->width() );
    new TQRadioButton( i18n("&Portrait"), m_orientGroup );

    TQLabel* lbLandscape = new TQLabel( m_orientGroup );
    lbLandscape->setPixmap( TQPixmap( UserIcon( "koLandscape" ) ) );
    lbLandscape->setMaximumWidth( lbLandscape->pixmap()->width() );
    new TQRadioButton( i18n("La&ndscape"), m_orientGroup );

    connect( m_orientGroup, TQT_SIGNAL (clicked (int)), this, TQT_SLOT( orientationChanged(int) ));

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

    TQGridLayout *marginsLayout = new TQGridLayout( marginsFrame->layout(), 3, 3,
       KDialog::spacingHint() );

    // left margin
    ebrLeft = new KoUnitDoubleSpinBox( marginsFrame, "Left" );
    marginsLayout->addWidget( ebrLeft, 1, 0 );
    connect( ebrLeft, TQT_SIGNAL( valueChangedPt( double ) ), this, TQT_SLOT( leftChanged( double ) ) );

    // right margin
    ebrRight = new KoUnitDoubleSpinBox( marginsFrame, "Right" );
    marginsLayout->addWidget( ebrRight, 1, 2 );
    connect( ebrRight, TQT_SIGNAL( valueChangedPt( double ) ), this, TQT_SLOT( rightChanged( double ) ) );

    // top margin
    ebrTop = new KoUnitDoubleSpinBox( marginsFrame, "Top" );
    marginsLayout->addWidget( ebrTop, 0, 1 , TQt::AlignCenter );
    connect( ebrTop, TQT_SIGNAL( valueChangedPt( double ) ), this, TQT_SLOT( topChanged( double ) ) );

    // bottom margin
    ebrBottom = new KoUnitDoubleSpinBox( marginsFrame, "Bottom" );
    marginsLayout->addWidget( ebrBottom, 2, 1, TQt::AlignCenter );
    connect( ebrBottom, TQT_SIGNAL( valueChangedPt( double ) ), this, TQT_SLOT( bottomChanged( double ) ) );

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

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

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

void KoPageLayoutSize::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();
    emit propertyChange(m_layout);
}

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

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

    setUnit( m_unit );
    updatePreview();
}

void KoPageLayoutSize::setUnit( KoUnit::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, KoUnit::fromUserValue( 9999, m_unit ), KoUnit::fromUserValue( 0.01, m_unit ) );
    epgWidth->changeValue( m_layout.ptWidth );

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

    double dStep = KoUnit::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 KoPageLayoutSize::setUnitInt( int unit ) {
    setUnit((KoUnit::Unit)unit);
}

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

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

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

    updatePreview( );
    emit propertyChange(m_layout);
}

void KoPageLayoutSize::orientationChanged(int which) {
    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 KoPageLayoutSize::widthChanged(double width) {
    if(m_blockSignals) return;
    m_layout.ptWidth = width;
    updatePreview();
    emit propertyChange(m_layout);
}
void KoPageLayoutSize::heightChanged(double height) {
    if(m_blockSignals) return;
    m_layout.ptHeight = height;
    updatePreview( );
    emit propertyChange(m_layout);
}
void KoPageLayoutSize::leftChanged( double left ) {
    if(m_blockSignals) return;
    m_layout.ptLeft = left;
    updatePreview();
    emit propertyChange(m_layout);
}
void KoPageLayoutSize::rightChanged(double right) {
    if(m_blockSignals) return;
    m_layout.ptRight = right;
    updatePreview();
    emit propertyChange(m_layout);
}
void KoPageLayoutSize::topChanged(double top) {
    if(m_blockSignals) return;
    m_layout.ptTop = top;
    updatePreview();
    emit propertyChange(m_layout);
}
void KoPageLayoutSize::bottomChanged(double bottom) {
    if(m_blockSignals) return;
    m_layout.ptBottom = bottom;
    updatePreview();
    emit propertyChange(m_layout);
}

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

void KoPageLayoutSize::setColumns(KoColumns &columns) {
    pgPreview->setPageColumns(columns);
}

#include <KoPageLayoutSize.moc>