/* This file is part of the KDE project
   Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
   Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>

   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.

   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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include <qtoolbutton.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qvalidator.h>
#include <qtooltip.h>
#include <qscrollview.h>

#include <klocale.h>
#include <kiconloader.h>
#include <klineedit.h>

#include "kexirecordnavigator.h"
#include "kexirecordmarker.h"

class KexiRecordNavigatorPrivate
{
	public:
		KexiRecordNavigatorPrivate()
		 : handler(0)
		 , editingIndicatorLabel(0)
		 , editingIndicatorEnabled(false)
		 , editingIndicatorVisible(false)
		{
		}
		KexiRecordNavigatorHandler *handler;
		QHBoxLayout *lyr;

		QLabel *editingIndicatorLabel;
		bool editingIndicatorEnabled : 1;
		bool editingIndicatorVisible : 1;
};

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

KexiRecordNavigatorHandler::KexiRecordNavigatorHandler()
{
}

KexiRecordNavigatorHandler::~KexiRecordNavigatorHandler()
{
}

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

KexiRecordNavigator::KexiRecordNavigator(QWidget *parent, int leftMargin, const char *name)
 : QFrame(parent, name)
 , m_view(0)
 , m_isInsertingEnabled(true)
 , d( new KexiRecordNavigatorPrivate() )
{
	if (parent->inherits("QScrollView"))
		setParentView( dynamic_cast<QScrollView*>(parent) );
	setFrameStyle(QFrame::NoFrame);
	d->lyr = new QHBoxLayout(this,0,0,"nav_lyr");

	m_textLabel = new QLabel(this);
	d->lyr->addWidget( m_textLabel  );
	setLabelText(i18n("Row:"));
		
	int bw = 6+SmallIcon("navigator_first").width(); //QMIN( horizontalScrollBar()->height(), 20);
	QFont f = font();
	f.setPixelSize((bw > 12) ? 12 : bw);
	QFontMetrics fm(f);
	m_nav1DigitWidth = fm.width("8");

	d->lyr->addWidget( m_navBtnFirst = new QToolButton(this) );
	m_navBtnFirst->setFixedWidth(bw);
	m_navBtnFirst->setFocusPolicy(NoFocus);
	m_navBtnFirst->setIconSet( SmallIconSet("navigator_first") );
	QToolTip::add(m_navBtnFirst, i18n("First row"));
	
	d->lyr->addWidget( m_navBtnPrev = new QToolButton(this) );
	m_navBtnPrev->setFixedWidth(bw);
	m_navBtnPrev->setFocusPolicy(NoFocus);
	m_navBtnPrev->setIconSet( SmallIconSet("navigator_prev") );
	m_navBtnPrev->setAutoRepeat(true);
	QToolTip::add(m_navBtnPrev, i18n("Previous row"));
	
	d->lyr->addSpacing( 6 );
	
	d->lyr->addWidget( m_navRecordNumber = new KLineEdit(this) );
	m_navRecordNumber->setAlignment(AlignRight | AlignVCenter);
	m_navRecordNumber->setFocusPolicy(ClickFocus);
	m_navRecordNumber->installEventFilter(this);
//	m_navRowNumber->setFixedWidth(fw);
	m_navRecordNumberValidator = new QIntValidator(1, INT_MAX, this);
	m_navRecordNumber->setValidator(m_navRecordNumberValidator);
	m_navRecordNumber->installEventFilter(this);
	QToolTip::add(m_navRecordNumber, i18n("Current row number"));
	
	KLineEdit *lbl_of = new KLineEdit(i18n("of"), this);
	lbl_of->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred);
	lbl_of->setMaximumWidth(fm.width(lbl_of->text())+8);
	lbl_of->setReadOnly(true);
	lbl_of->setLineWidth(0);
	lbl_of->setFocusPolicy(NoFocus);
	lbl_of->setAlignment(AlignCenter);
	d->lyr->addWidget( lbl_of );
	
	d->lyr->addWidget( m_navRecordCount = new KLineEdit(this) );
	m_navRecordCount->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred);
	m_navRecordCount->setReadOnly(true);
	m_navRecordCount->setLineWidth(0);
	m_navRecordCount->setFocusPolicy(NoFocus);
	m_navRecordCount->setAlignment(AlignLeft | AlignVCenter);
	QToolTip::add(m_navRecordCount, i18n("Number of rows"));

	lbl_of->setFont(f);
	m_navRecordNumber->setFont(f);
	m_navRecordCount->setFont(f);
	setFont(f);

	d->lyr->addWidget( m_navBtnNext = new QToolButton(this) );
	m_navBtnNext->setFixedWidth(bw);
	m_navBtnNext->setFocusPolicy(NoFocus);
	m_navBtnNext->setIconSet( SmallIconSet("navigator_next") );
	m_navBtnNext->setAutoRepeat(true);
	QToolTip::add(m_navBtnNext, i18n("Next row"));
	
	d->lyr->addWidget( m_navBtnLast = new QToolButton(this) );
	m_navBtnLast->setFixedWidth(bw);
	m_navBtnLast->setFocusPolicy(NoFocus);
	m_navBtnLast->setIconSet( SmallIconSet("navigator_last") );
	QToolTip::add(m_navBtnLast, i18n("Last row"));
	
	d->lyr->addSpacing( 6 );
	d->lyr->addWidget( m_navBtnNew = new QToolButton(this) );
	m_navBtnNew->setFixedWidth(bw);
	m_navBtnNew->setFocusPolicy(NoFocus);
	m_navBtnNew->setIconSet( SmallIconSet("navigator_new") );
	QToolTip::add(m_navBtnNew, i18n("New row"));
	m_navBtnNext->setEnabled(isInsertingEnabled());
	
	d->lyr->addSpacing( 6 );
	d->lyr->addStretch(10);

	connect(m_navBtnPrev,SIGNAL(clicked()),this,SLOT(slotPrevButtonClicked()));
	connect(m_navBtnNext,SIGNAL(clicked()),this,SLOT(slotNextButtonClicked()));
	connect(m_navBtnLast,SIGNAL(clicked()),this,SLOT(slotLastButtonClicked()));
	connect(m_navBtnFirst,SIGNAL(clicked()),this,SLOT(slotFirstButtonClicked()));
	connect(m_navBtnNew,SIGNAL(clicked()),this,SLOT(slotNewButtonClicked()));

	setRecordCount(0);
	setCurrentRecordNumber(0);

	updateGeometry(leftMargin);
}

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

void KexiRecordNavigator::setInsertingEnabled(bool set)
{
	if (m_isInsertingEnabled==set)
		return;
	m_isInsertingEnabled = set;
	if (isEnabled())
		m_navBtnNew->setEnabled( m_isInsertingEnabled );
}

void KexiRecordNavigator::setEnabled( bool set )
{
	QFrame::setEnabled(set);
	if (set && !m_isInsertingEnabled)
		m_navBtnNew->setEnabled( false );
}

bool KexiRecordNavigator::eventFilter( QObject *o, QEvent *e )
{
	if (o==m_navRecordNumber) {
		bool recordEntered = false;
		bool ret;
		if (e->type()==QEvent::KeyPress) {
			QKeyEvent *ke = static_cast<QKeyEvent*>(e);
			switch (ke->key()) {
			case Qt::Key_Escape: {
				ke->accept();
				m_navRecordNumber->undo();
				if (m_view)
					m_view->setFocus();
				return true;
			}
			case Qt::Key_Enter:
			case Qt::Key_Return:
			case Qt::Key_Tab:
			case Qt::Key_BackTab: 
			{
				recordEntered=true;
				ke->accept(); //to avoid pressing Enter later
				ret = true;
			}
			default:;
			}
		}
		else if (e->type()==QEvent::FocusOut) {
			if (static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Tab
				&& static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Backtab
				&& static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Other)
				recordEntered=true;
			ret = false;
		}

		if (recordEntered) {
			bool ok=true;
			uint r = m_navRecordNumber->text().toUInt(&ok);
			if (!ok || r<1)
				r = (recordCount()>0)?1:0;
			if (m_view && (hasFocus() || e->type()==QEvent::KeyPress))
				m_view->setFocus();
			setCurrentRecordNumber(r);
			emit recordNumberEntered(r);
			if (d->handler)
				d->handler->moveToRecordRequested(r-1);
			return ret;
		}
	}
/*
	bool ok=true;
	int r = text.toInt(&ok);
	if (!ok || r<1)
		r = 1;
	emit recordNumberEntered(r);*/
	return false;
}

void KexiRecordNavigator::setCurrentRecordNumber(uint r)
{
	uint recCnt = recordCount();
	if (r>(recCnt+(m_isInsertingEnabled?1:0)))
		r = recCnt+(m_isInsertingEnabled?1:0);
	QString n;
	if (r>0)
		n = QString::number(r);
	else
		n = " ";
//	if (d->navRecordNumber->text().length() != n.length()) {//resize
//		d->navRecordNumber->setFixedWidth(
//			d->nav1DigitWidth*QMAX( QMAX(n.length(),2)+1,d->navRecordCount->text().length()+1)+6 
//		);
//	}

	m_navRecordNumber->setText(n);
	m_navRecordCount->deselect();
	updateButtons(recCnt);
}

void KexiRecordNavigator::updateButtons(uint recCnt)
{
	const uint r = currentRecordNumber();
	if (isEnabled()) {
		m_navBtnPrev->setEnabled(r > 1);
		m_navBtnFirst->setEnabled(r > 1);
		m_navBtnNext->setEnabled(r > 0 
			&& r < (recCnt +(m_isInsertingEnabled?(1+d->editingIndicatorVisible/*if we're editing, next btn is avail.*/):0) ) );
		m_navBtnLast->setEnabled(r!=(recCnt+(m_isInsertingEnabled?1:0)) && (m_isInsertingEnabled || recCnt>0));
	}
}

void KexiRecordNavigator::setRecordCount(uint count)
{
	const QString & n = QString::number(count);
	if (m_isInsertingEnabled && currentRecordNumber()==0) {
		setCurrentRecordNumber(1);
	}
	if (m_navRecordCount->text().length() != n.length()) {//resize
		m_navRecordCount->setFixedWidth(m_nav1DigitWidth*n.length()+6);
		
		if (m_view && m_view->horizontalScrollBar()->isVisible()) {
			//+width of the delta
			resize(width()+(n.length()-m_navRecordCount->text().length())*m_nav1DigitWidth, height());
//			horizontalScrollBar()->move(d->navPanel->x()+d->navPanel->width()+20,horizontalScrollBar()->y());
		}
	}
	//update row number widget's width
	const int w = m_nav1DigitWidth*QMAX( QMAX(n.length(),2)+1,m_navRecordNumber->text().length()+1)+6;
	if (m_navRecordNumber->width()!=w) //resize
		m_navRecordNumber->setFixedWidth(w);

	m_navRecordCount->setText(n);
	m_navRecordCount->deselect();
	if (m_view)
		m_view->updateScrollBars();
	updateButtons(recordCount());
}

uint KexiRecordNavigator::currentRecordNumber() const
{
	bool ok=true;
	int r = m_navRecordNumber->text().toInt(&ok);
	if (!ok || r<1)
		r = 0;
	return r;
}

uint KexiRecordNavigator::recordCount() const
{
	bool ok=true;
	int r = m_navRecordCount->text().toInt(&ok);
	if (!ok || r<1)
		r = 0;
	return r;
}

void KexiRecordNavigator::setParentView(QScrollView *view)
{
	m_view = view;
}

void KexiRecordNavigator::updateGeometry(int leftMargin)
{
	QFrame::updateGeometry();
	if (m_view) {
		int navWidth;
		if (m_view->horizontalScrollBar()->isVisible()) {
			navWidth = sizeHint().width();
		}
		else {
			navWidth = leftMargin + m_view->clipper()->width();
		}
		
		setGeometry(
			m_view->frameWidth(),
			m_view->height() - m_view->horizontalScrollBar()->sizeHint().height()-m_view->frameWidth(),
			navWidth,
			m_view->horizontalScrollBar()->sizeHint().height()
		);

		m_view->updateScrollBars();
	}
}

void KexiRecordNavigator::setHBarGeometry( QScrollBar & hbar, int x, int y, int w, int h )
{
	hbar.setGeometry( x + width(), y, w - width(), h );
}

void KexiRecordNavigator::setLabelText(const QString& text)
{
	m_textLabel->setText(text.isEmpty() ? QString::null : (QString::fromLatin1(" ")+text+" "));
}

void KexiRecordNavigator::setInsertingButtonVisible(bool set)
{
	if (set)
		m_navBtnNew->show();
	else
		m_navBtnNew->hide();
}

void KexiRecordNavigator::slotPrevButtonClicked()
{
	emit prevButtonClicked();
	if (d->handler)
		d->handler->moveToPreviousRecordRequested();
}

void KexiRecordNavigator::slotNextButtonClicked()
{
	emit nextButtonClicked();
	if (d->handler)
		d->handler->moveToNextRecordRequested();
}

void KexiRecordNavigator::slotLastButtonClicked()
{
	emit lastButtonClicked();
	if (d->handler)
		d->handler->moveToLastRecordRequested();
}

void KexiRecordNavigator::slotFirstButtonClicked()
{
	emit firstButtonClicked();
	if (d->handler)
		d->handler->moveToFirstRecordRequested();
}

void KexiRecordNavigator::slotNewButtonClicked()
{
	emit newButtonClicked();
	if (d->handler)
		d->handler->addNewRecordRequested();
}


void KexiRecordNavigator::setRecordHandler(KexiRecordNavigatorHandler *handler)
{
	d->handler = handler;
}

bool KexiRecordNavigator::editingIndicatorVisible() const
{
	return d->editingIndicatorVisible;
}

bool KexiRecordNavigator::editingIndicatorEnabled() const
{
	return d->editingIndicatorEnabled;
}

void KexiRecordNavigator::setEditingIndicatorEnabled(bool set)
{
	d->editingIndicatorEnabled = set;
	if (d->editingIndicatorEnabled) {
		if (!d->editingIndicatorLabel) {
			d->editingIndicatorLabel = new QLabel(this);
			d->editingIndicatorLabel->setAlignment(Qt::AlignCenter);
			QPixmap pix;
			pix.convertFromImage( *KexiRecordMarker::penImage() );
			d->editingIndicatorLabel->setFixedWidth( pix.width() + 2*2 );
			d->lyr->insertWidget( 0, d->editingIndicatorLabel );
		}
		d->editingIndicatorLabel->show();
	}
	else {
		if (d->editingIndicatorLabel) {
			d->editingIndicatorLabel->hide();
		}
	}
}

void KexiRecordNavigator::showEditingIndicator(bool show)
{
	d->editingIndicatorVisible = show;
	updateButtons(recordCount()); //this will refresh 'next btn'
	if (!d->editingIndicatorEnabled)
		return;
	if (d->editingIndicatorVisible) {
		QPixmap pix;
		pix.convertFromImage( *KexiRecordMarker::penImage() );
		d->editingIndicatorLabel->setPixmap( pix );
		QToolTip::add( d->editingIndicatorLabel, i18n("Editing indicator") );
	}
	else {
		d->editingIndicatorLabel->setPixmap( QPixmap() );
		QToolTip::remove( d->editingIndicatorLabel );
	}
}

#include "kexirecordnavigator.moc"
