/**
 * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS.
 *
 * 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, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <qtabdialog.h>
#include <qmultilineedit.h>
#include <qbuttongroup.h>
#include <qradiobutton.h>
#include <qlabel.h>
#include <qcombobox.h>
#include <qlayout.h>
#include <stdio.h>
#include <qstring.h>
#include <qpainter.h>
#include <qdrawutil.h>
#include <qtooltip.h>
#include <qscrollbar.h>

#include <kapplication.h>
#include <kaction.h>
#include <kpopupmenu.h>
#include <klocale.h>

#include "marklist.moc"

#define FLAG_WIDTH 20

MarkListTable::MarkListTable( QWidget * parent , const char * name ) :
    QtTableView( parent, name ),
    _sel( -1 ),
    _drag( -1 )
{
    setFrameStyle( Panel | Sunken );
    setLineWidth( 1 );
    setTableFlags( Tbl_autoVScrollBar | Tbl_snapToVGrid
                   | Tbl_clipCellPainting );
    setCellHeight( fontMetrics().lineSpacing() + 4 );
    setNumCols( 2 );

    _markCurrent = new KAction( i18n( "Mark Current Page" ), 0,
                                this, SLOT( markCurrent() ), this );
    _markAll     = new KAction( i18n( "Mark &All Pages" ), 0,
                                this, SLOT( markAll() ), this );
    _markEven    = new KAction( i18n( "Mark &Even Pages" ), 0,
                                this, SLOT( markEven() ), this );
    _markOdd     = new KAction( i18n( "Mark &Odd Pages" ), 0,
                                this, SLOT( markOdd() ), this );
    _toggleMarks = new KAction( i18n( "&Toggle Page Marks"), 0,
                                this, SLOT( toggleMarks() ), this );
    _removeMarks = new KAction( i18n( "&Remove Page Marks" ), 0,
                                this, SLOT( removeMarks() ), this );

    _actionMenu = new KActionMenu( i18n( "&Page Marks" ), this );
    _actionMenu->insert( _markCurrent );
    _actionMenu->insert( _markAll );
    _actionMenu->insert( _markEven );
    _actionMenu->insert( _markOdd );
    _actionMenu->insert( _toggleMarks );
    _actionMenu->insert( _removeMarks );
    _items.setAutoDelete( true );

    initPixmaps();
}

MarkListTable::~MarkListTable()
{
  delete _flag;
  delete _bullet;
}

void MarkListTable::initPixmaps()
{
    QColorGroup cg = QApplication::palette().active();

    int w = cellWidth( 0 );
    int h = cellHeight( 0 );
    int xOffset, yOffset;

    _flag   = new QPixmap( w, h );
    _bullet = new QPixmap( w, h );

    QPainter p;
    QBrush brush( cg.base() );

    xOffset = 6;
    yOffset = 3;

    p.begin( _flag );
    p.fillRect( 0, 0, w, h, brush );
    p.drawLine( xOffset + 4, yOffset,     xOffset + 4, yOffset + 9 );
    p.setPen( red );
    p.drawLine( xOffset + 3, yOffset + 1, xOffset,     yOffset + 4 );
    p.drawLine( xOffset + 3, yOffset + 1, xOffset + 3, yOffset + 4 );
    p.drawLine( xOffset,     yOffset + 4, xOffset + 3, yOffset + 4 );
    p.end();

    xOffset = 4;
    yOffset = 5;

    p.begin( _bullet );
    p.fillRect( 0, 0, w, h, brush );
    p.setPen( cg.dark() );
    p.setBrush( cg.dark() );
    p.drawEllipse( xOffset + 4, yOffset, 4, 4 );
    p.setPen( white );
    p.drawPoint( xOffset + 5, yOffset + 1 );
    p.end();
}

void MarkListTable::insertItem ( const QString& text, int index,
                                 const QString& tip )
{
    _items.insert( index, new MarkListTableItem( text, tip ) );
    setNumRows( _items.count() );
}

void MarkListTable::setAutoUpdate( bool enable )
{
    QtTableView::setAutoUpdate( enable );
    if( enable )
	repaint();
}

void MarkListTable::clear()
{
    QColorGroup cg = QApplication::palette().active();
    setBackgroundColor( cg.base() );
    _items.clear();
    setNumRows( _items.count() );
    _sel = -1;
    update();
}

int MarkListTable::cellWidth( int col )
{
    if( col == 0 )
	return FLAG_WIDTH;
    else
	return width() - FLAG_WIDTH - 2*frameWidth();
}

void MarkListTable::paintCell( QPainter* p, int row, int col )
{
    QColorGroup cg = QApplication::palette().active();

    if( col == 0 )
    {
	if( _items.at( row )->isMarked() )
	    p->drawPixmap( 0, 0, *_flag );
	else
	    p->drawPixmap( 0, 0, *_bullet );
    }
    else if( col == 1 )
    {
	int w = cellWidth( col );
	int h = cellHeight( row );
	QBrush brush;

	if( _items.at( row )->isSelected() )
	{
	    brush = cg.highlight();
	    p->setPen( cg.highlightedText() );
	}
	else
	{
	    brush = cg.base();
	    p->setPen(cg.text());
	}

	p->fillRect( 0, 0, w, h, brush );
	p->drawText( 0, 0, w, h, AlignCenter, _items.at( row )->text() );

	QToolTip::add( this, QRect(0,0,w,h), _items.at( row )->tip() );
    }
}

void MarkListTable::mousePressEvent( QMouseEvent* e )
{
    int row = findRow( e->pos().y() );
    int col = findCol( e->pos().x() );

    if( row == -1 )
	return;

    MarkListTableItem* it = _items.at( row );

    if( e->button() == LeftButton )
    {
	switch( col )
	{
	case 0: //flags
	    it->toggle();
	    updateCell( row, 0 );
	    _drag = row;
	    break;
	case 1: //page numbers
	    select( row );
	    _drag = -1;
	    break;
	}
    }
    else if( e->button() == MidButton )
    {
	it->toggle();
	updateCell( row, 0 );
	_drag = row;
    }
    else if( e->button() == RightButton )
	_actionMenu->popup( mapToGlobal( e->pos() ) );
}

void MarkListTable::mouseMoveEvent( QMouseEvent* e )
{
    if( e->state() != MidButton && e->state() != LeftButton || _drag == -1 )
	return;

    int row = findRow( e->pos().y() );
    if( row == _drag || row == -1 )
	return;

    do {
	_drag += row > _drag ? 1 : -1;
	_items.at( _drag )->toggle();
	updateCell( _drag, 0 );
    } while ( row != _drag );
}

void MarkListTable::wheelEvent( QWheelEvent* e )
{
    if( verticalScrollBar() )
	QApplication::sendEvent( verticalScrollBar(), e );
}

QString MarkListTable::text( int index )
{
    if( index < 0 || index > (int) _items.count() )
	return 0;

    return _items.at( index )->text();
}

void MarkListTable::select( int i )
{
    if( i < 0 || i >= (signed) _items.count() || i == _sel )
	return;

    if( _sel != -1 )
    {
	_items.at( _sel )->setSelected( false );
	updateCell( _sel, 0 );
	updateCell( _sel, 1 );
    }

    _sel = i;
    _items.at( i )->setSelected( true );
    updateCell( i, 0 );
    updateCell( i, 1 );

    emit selected( i );

    if( ( i <= 0 || rowIsVisible( i - 1 ) )
     && ( i>= (signed) _items.count() - 1 || rowIsVisible( i + 1 ) ) )
	return;

    setTopCell( QMAX( 0, i - viewHeight()/cellHeight()/2 ) );
}

void MarkListTable::markCurrent()
{
    if( _sel == -1 )
	return;

    _items.at( _sel )->toggle();
    updateCell( _sel, 0 );
}

void MarkListTable::markAll()
{
    changeMarks( 1 );
}

void MarkListTable::markEven()
{
    changeMarks( 1, 2 );
}

void MarkListTable::markOdd()
{
    changeMarks( 1, 1 );
}

void MarkListTable::removeMarks()
{
    changeMarks( 0 );
}

void MarkListTable::toggleMarks()
{
    changeMarks( 2 );
}

int MarkListTable::rowHeight() const
{
    return cellHeight();
}

void MarkListTable::changeMarks( int how, int which )
{
    MarkListTableItem *it;
    QString t;

    setUpdatesEnabled( false );
    for( int i = 0; i < (signed) _items.count(); ++i )
    {
	if ( which && (i + 1) % 2 == which - 1 )
	    continue;
	it = _items.at( i );
	if ( how == 2 )
	    it->toggle();
	else
	    it->setMarked( how );
	updateCell( i, 0 );
    }
    setUpdatesEnabled( true );

    repaint();
}

QValueList<int> MarkListTable::markList() const
{
    QValueList<int> l;
    QPtrListIterator< MarkListTableItem > it( _items );
    unsigned int i = 1;

    for( ; it.current(); ++it, ++i )
    {
	if( it.current()->isMarked() )
	    l.append( i );
    }

    return l;
}

//------------------------------------------------------------------

MarkList::MarkList( QWidget* parent, const char* name)
  : QWidget( parent, name )
{
    _table = new MarkListTable ( this );
    _table->setFocusProxy( this );

    _markLabel = new QLabel ( this );
    _markLabel->setFocusProxy( this );
    _markLabel->setFrameStyle( QFrame::Panel | QFrame::Raised );
    _markLabel->setLineWidth( 1 );
    _markLabel->setMargin( 1 );
    _markLabel->setPixmap( flagPixmap() );

    _pageLabel = new QLabel ( this );
    _pageLabel->setFocusProxy( this );
    _pageLabel->setFrameStyle( QFrame::Panel | QFrame::Raised );
    _pageLabel->setLineWidth( 1 );
    _pageLabel->setMargin( 1 );
    _pageLabel->setText( i18n("Page") );

    connect( _table, SIGNAL( selected( int ) ),
	     this, SIGNAL( selected( int ) ) );
}

void MarkList::resizeEvent( QResizeEvent* )
{
    _markLabel->setGeometry( 0, 0, FLAG_WIDTH, _table->rowHeight() + 4 );
    _pageLabel->setGeometry( FLAG_WIDTH, 0,
			     width() - FLAG_WIDTH, _table->rowHeight() + 4 );
    _table->setGeometry( 0, _pageLabel->height(),
			 width(), height() - _pageLabel->height() );
}

void MarkList::wheelEvent( QWheelEvent* e )
{
    QApplication::sendEvent( _table, e );
}

QPixmap MarkList::flagPixmap()
{
    QColorGroup cg = QApplication::palette().active();

    QPixmap pm;
    pm.resize(16,16);
    pm.fill( cg.background() );

    int xOffset = 4;
    int yOffset = 3;

    QPainter p;
    p.begin( &pm );
    p.setPen( cg.text() );
    p.drawLine( xOffset + 4, yOffset,     xOffset + 4, yOffset + 9 );
    p.setPen( red );
    p.drawLine( xOffset + 3, yOffset + 1, xOffset,     yOffset + 4 );
    p.drawLine( xOffset + 3, yOffset + 1, xOffset + 3, yOffset + 4 );
    p.drawLine( xOffset,     yOffset + 4, xOffset + 3, yOffset + 4 );
    p.end();

    return pm;
}
