/* This file is part of the KDE project
   Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
   Copyright (C) 2004  Alexander Dymo <cloudtemple@mskat.net>

   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; either
   version 2 of the License, or (at your option) any later version.

   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 "spinbox.h"

#include "property.h"

#include <tqlayout.h>
#include <tqobjectlist.h>
#include <tqvariant.h>
#include <tqpainter.h>
#include <tqlineedit.h>

#include <tdeglobal.h>
#include <tdelocale.h>

using namespace KoProperty;

IntSpinBox::IntSpinBox(int lower, int upper, int step, int value, int base, IntEdit *parent, const char *name)
: KIntSpinBox(lower, upper, step, value, base, parent, name)
{
	editor()->setAlignment(TQt::AlignLeft);
	installEventFilter(editor());
	installEventFilter(this);
	TQObjectList *spinwidgets = queryList( "TQSpinWidget", 0, false, true );
	TQSpinWidget* spin = static_cast<TQSpinWidget*>(spinwidgets->first());
	if (spin)
		spin->installEventFilter(this);
	delete spinwidgets;
}

void IntSpinBox::setValue(const TQVariant &value)
{
	if (dynamic_cast<IntEdit*>(parentWidget()) && dynamic_cast<IntEdit*>(parentWidget())->isReadOnly())
		return;
	if (value.isNull())
		editor()->clear();
	else
		KIntSpinBox::setValue(value.toInt());
}

bool
IntSpinBox::eventFilter(TQObject *o, TQEvent *e)
{
	if(o == editor())
	{
		if(e->type() == TQEvent::KeyPress)
		{
			TQKeyEvent* ev = static_cast<TQKeyEvent*>(e);
			if((ev->key()==Key_Up || ev->key()==Key_Down) && ev->state() !=ControlButton)
			{
				parentWidget()->eventFilter(o, e);
				return true;
			}
		}
	}
	if ((o == editor() || o == this || o->parent() == this) 
		&& e->type() == TQEvent::Wheel && static_cast<IntEdit*>(parentWidget())->isReadOnly())
	{
		return true; //avoid value changes for read-only widget
	}

	return KIntSpinBox::eventFilter(o, e);
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

IntEdit::IntEdit(Property *property, TQWidget *parent, const char *name)
 : Widget(property, parent, name)
{
	TQVariant minVal( property ? property->option("min") : 0 );
	TQVariant maxVal( property ? property->option("max") : TQVariant() );
	TQVariant minValueText( property ? property->option("minValueText") : TQVariant() );
	if (minVal.isNull())
		minVal = 0;
	if (maxVal.isNull())
		maxVal = INT_MAX;

	m_edit = new IntSpinBox(minVal.toInt(), maxVal.toInt(), 1, 0, 10, this);
	if (!minValueText.isNull())
		m_edit->setSpecialValueText(minValueText.toString());
	m_edit->setMinimumHeight(5);
	setEditor(m_edit);

	setLeavesTheSpaceForRevertButton(true);
	setFocusWidget(m_edit);
	connect(m_edit, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(slotValueChanged(int)));
}

IntEdit::~IntEdit()
{}

TQVariant
IntEdit::value() const
{
	if (m_edit->cleanText().isEmpty())
		return TQVariant();
	return m_edit->value();
}

void
IntEdit::setValue(const TQVariant &value, bool emitChange)
{
	m_edit->blockSignals(true);
	m_edit->setValue(value);
	updateSpinWidgets();
	m_edit->blockSignals(false);
	if (emitChange)
		emit valueChanged(this);
}

void
IntEdit::drawViewer(TQPainter *p, const TQColorGroup &cg, const TQRect &r, const TQVariant &value)
{
	TQString valueText = value.toString();
	if (property() && property()->hasOptions()) {
		//replace min value with minValueText if defined
		TQVariant minValue( property()->option("min") );
		TQVariant minValueText( property()->option("minValueText") );
		if (!minValue.isNull() && !minValueText.isNull() && minValue.toInt() == value.toInt()) {
			valueText = minValueText.toString();
		}
	}

	Widget::drawViewer(p, cg, r, valueText);
//	p->eraseRect(r);
//	p->drawText(r, TQt::AlignLeft | TQt::AlignVCenter | TQt::SingleLine, valueText);
}

void
IntEdit::slotValueChanged(int)
{
	emit valueChanged(this);
}

void
IntEdit::updateSpinWidgets()
{
	TQObjectList *spinwidgets = queryList( "TQSpinWidget", 0, false, true );
	TQSpinWidget* spin = static_cast<TQSpinWidget*>(spinwidgets->first());
	if (spin) {
		spin->setUpEnabled(!isReadOnly());
		spin->setDownEnabled(!isReadOnly());
	}
	delete spinwidgets;
}

void
IntEdit::setReadOnlyInternal(bool readOnly)
{
	//disable editor and spin widget
	m_edit->editor()->setReadOnly(readOnly);
	updateSpinWidgets();
	if (readOnly)
		setLeavesTheSpaceForRevertButton(false);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DoubleSpinBox::DoubleSpinBox (double lower, double upper, double step, double value, int precision, DoubleEdit *parent)
: KDoubleSpinBox(lower, upper, step, value, precision, parent)
{
	editor()->setAlignment(TQt::AlignLeft);
	installEventFilter(editor());
	installEventFilter(this);
	TQObjectList *spinwidgets = queryList( "TQSpinWidget", 0, false, true );
	TQSpinWidget* spin = static_cast<TQSpinWidget*>(spinwidgets->first());
	if (spin)
		spin->installEventFilter(this);
	delete spinwidgets;
}

bool
DoubleSpinBox::eventFilter(TQObject *o, TQEvent *e)
{
	if(o == editor())
	{
		if(e->type() == TQEvent::KeyPress)
		{
			TQKeyEvent* ev = static_cast<TQKeyEvent*>(e);
			if((ev->key()==Key_Up || ev->key()==Key_Down) && ev->state()!=ControlButton)
			{
				parentWidget()->eventFilter(o, e);
				return true;
			}
		}
	}
	if ((o == editor() || o == this || o->parent() == this) 
		&& e->type() == TQEvent::Wheel && static_cast<IntEdit*>(parentWidget())->isReadOnly())
	{
		return true; //avoid value changes for read-only widget
	}

	return KDoubleSpinBox::eventFilter(o, e);
}


void DoubleSpinBox::setValue( const TQVariant& value )
{
	if (dynamic_cast<DoubleEdit*>(parentWidget()) && dynamic_cast<DoubleEdit*>(parentWidget())->isReadOnly())
		return;
	if (value.isNull())
		editor()->clear();
	else
		KDoubleSpinBox::setValue(value.toDouble());
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DoubleEdit::DoubleEdit(Property *property, TQWidget *parent, const char *name)
 : Widget(property, parent, name)
{
	TQVariant minVal( property ? property->option("min") : 0 );
	TQVariant maxVal( property ? property->option("max") : TQVariant() );
	TQVariant step( property ? property->option("step") : TQVariant());
	TQVariant precision( property ? property->option("precision") : TQVariant());
	TQVariant minValueText( property ? property->option("minValueText") : TQVariant() );
	if (minVal.isNull())
		minVal = 0;
	if (maxVal.isNull())
		maxVal = (double)(INT_MAX/100);
	if(step.isNull())
		step = 0.1;
	if(precision.isNull())
		precision = 2;

	m_edit = new DoubleSpinBox(minVal.toDouble(), maxVal.toDouble(), step.toDouble(),
		 0, precision.toInt(), this);
	if (!minValueText.isNull())
		m_edit->setSpecialValueText(minValueText.toString());
	m_edit->setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding);
	m_edit->setMinimumHeight(5);
	setEditor(m_edit);

	setLeavesTheSpaceForRevertButton(true);
	setFocusWidget(m_edit);
	connect(m_edit, TQ_SIGNAL(valueChanged(double)), this, TQ_SLOT(slotValueChanged(double)));
}

DoubleEdit::~DoubleEdit()
{}

TQVariant
DoubleEdit::value() const
{
	if (m_edit->cleanText().isEmpty())
		return TQVariant();
	return m_edit->value();
}

void
DoubleEdit::setValue(const TQVariant &value, bool emitChange)
{
	m_edit->blockSignals(true);
	m_edit->setValue(value);
	updateSpinWidgets();
	m_edit->blockSignals(false);
	if (emitChange)
		emit valueChanged(this);
}

void
DoubleEdit::drawViewer(TQPainter *p, const TQColorGroup &cg, const TQRect &r, const TQVariant &value)
{
	TQString valueText;
	if (property() && property()->hasOptions()) {
		//replace min value with minValueText if defined
		TQVariant minValue( property()->option("min") );
		TQVariant minValueText( property()->option("minValueText") );
		if (!minValue.isNull() && !minValueText.isNull() && minValue.toString().toDouble() == value.toString().toDouble()) {
			valueText = minValueText.toString();
		}
	}
	if (valueText.isEmpty())
		valueText = TQString(value.toString()).replace('.', TDEGlobal::locale()->decimalSymbol());

	Widget::drawViewer(p, cg, r, valueText);
//	p->eraseRect(r);
//	p->drawText(r, TQt::AlignLeft | TQt::AlignVCenter | TQt::SingleLine, valueText);
}

void
DoubleEdit::slotValueChanged(double)
{
	emit valueChanged(this);
}

void
DoubleEdit::updateSpinWidgets()
{
	TQObjectList *spinwidgets = queryList( "TQSpinWidget", 0, false, true );
	TQSpinWidget* spin = static_cast<TQSpinWidget*>(spinwidgets->first());
	if (spin) {
		spin->setUpEnabled(!isReadOnly());
		spin->setDownEnabled(!isReadOnly());
	}
	delete spinwidgets;
}

void
DoubleEdit::setReadOnlyInternal(bool readOnly)
{
	//disable editor and spin widget
	m_edit->editor()->setReadOnly(readOnly);
	updateSpinWidgets();
	if (readOnly)
		setLeavesTheSpaceForRevertButton(false);
}

#include "spinbox.moc"
