/* This file is part of the KDE project Copyright (C) 2002, Rob Buis(buis@kde.org) Copyright (C) 2004, Nicolas GOUTTE 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 "koUnitWidgets.moc" #include #include #include #include #include // ---------------------------------------------------------------- // Support classes KoUnitDoubleValidator::KoUnitDoubleValidator( KoUnitDoubleBase *base, TQObject *parent, const char *name ) : KDoubleValidator( parent, name ), m_base( base ) { } TQValidator::State KoUnitDoubleValidator::validate( TQString &s, int &pos ) const { kdDebug(30004) << "KoUnitDoubleValidator::validate : " << s << " at " << pos << endl; TQValidator::State result = Acceptable; TQRegExp regexp ("([ a-zA-Z]+)$"); // Letters or spaces at end const int res = regexp.search( s ); if ( res == -1 ) { // Nothing like an unit? The user is probably editing the unit kdDebug(30004) << "Intermediate (no unit)" << endl; return Intermediate; } // ### TODO: are all the TQString::stripWhiteSpace really necessary? const TQString number ( s.left( res ).stripWhiteSpace() ); const TQString unitName ( regexp.cap( 1 ).stripWhiteSpace().lower() ); kdDebug(30004) << "Split:" << number << ":" << unitName << ":" << endl; bool ok = false; const double value = m_base->toDouble( number, &ok ); double newVal = 0.0; if( ok ) { KoUnit::Unit unit = KoUnit::unit( unitName, &ok ); if ( ok ) newVal = KoUnit::fromUserValue( value, unit ); else { // Probably the user is trying to edit the unit kdDebug(30004) << "Intermediate (unknown unit)" << endl; return Intermediate; } } else { kdWarning(30004) << "Not a number: " << number << endl; return Invalid; } newVal = KoUnit::ptToUnit( newVal, m_base->m_unit ); s = m_base->getVisibleText( newVal ); return result; } TQString KoUnitDoubleBase::getVisibleText( double value ) const { const TQString num ( TQString( "%1%2").tqarg( KGlobal::locale()->formatNumber( value, m_precision ), KoUnit::unitName( m_unit ) ) ); kdDebug(30004) << "getVisibleText: " << TQString::number( value, 'f', 12 ) << " => " << num << endl; return num; } double KoUnitDoubleBase::toDouble( const TQString& str, bool* ok ) const { TQString str2( str ); /* KLocale::readNumber wants the thousand separator exactly at 1000. But when editing, it might be anywhere. So we need to remove it. */ const TQString sep( KGlobal::locale()->thousandsSeparator() ); if ( !sep.isEmpty() ) str2.remove( sep ); str2.remove( KoUnit::unitName( m_unit ) ); const double dbl = KGlobal::locale()->readNumber( str2, ok ); if ( ok ) kdDebug(30004) << "toDouble:" << str << ": => :" << str2 << ": => " << TQString::number( dbl, 'f', 12 ) << endl; else kdWarning(30004) << "toDouble error:" << str << ": => :" << str2 << ":" << endl; return dbl; } // ---------------------------------------------------------------- // Widget classes KoUnitDoubleSpinBox::KoUnitDoubleSpinBox( TQWidget *parent, const char *name ) : KDoubleSpinBox( parent, name ), KoUnitDoubleBase( KoUnit::U_PT, 2 ) , m_lowerInPoints( -9999 ) , m_upperInPoints( 9999 ) , m_stepInPoints( 1 ) { KDoubleSpinBox::setPrecision( 2 ); m_validator = new KoUnitDoubleValidator( this, this ); TQSpinBox::setValidator( m_validator ); setAcceptLocalizedNumbers( true ); setUnit( KoUnit::U_PT ); connect(this, TQT_SIGNAL(valueChanged( double )), TQT_SLOT(privateValueChanged())); } KoUnitDoubleSpinBox::KoUnitDoubleSpinBox( TQWidget *parent, double lower, double upper, double step, double value, KoUnit::Unit unit, unsigned int precision, const char *name ) : KDoubleSpinBox( lower, upper, step, value, precision, parent, name ), KoUnitDoubleBase( unit, precision ), m_lowerInPoints( lower ), m_upperInPoints( upper ), m_stepInPoints( step ) { m_unit = KoUnit::U_PT; m_validator = new KoUnitDoubleValidator( this, this ); TQSpinBox::setValidator( m_validator ); setAcceptLocalizedNumbers( true ); setUnit( unit ); changeValue( value ); setLineStep( 0.5 ); connect(this, TQT_SIGNAL(valueChanged( double )), TQT_SLOT(privateValueChanged())); } void KoUnitDoubleSpinBox::changeValue( double val ) { KDoubleSpinBox::setValue( KoUnit::toUserValue( val, m_unit ) ); // TODO: emit valueChanged ONLY if the value was out-of-bounds // This will allow the 'user' dialog to set a dirty bool and ensure // a proper value is getting saved. } void KoUnitDoubleSpinBox::privateValueChanged() { emit valueChangedPt( value () ); } void KoUnitDoubleSpinBox::setUnit( KoUnit::Unit unit ) { double oldvalue = KoUnit::fromUserValue( KDoubleSpinBox::value(), m_unit ); KDoubleSpinBox::setMinValue( KoUnit::toUserValue( m_lowerInPoints, unit ) ); KDoubleSpinBox::setMaxValue( KoUnit::toUserValue( m_upperInPoints, unit ) ); KDoubleSpinBox::setLineStep( KoUnit::toUserValue( m_stepInPoints, unit ) ); KDoubleSpinBox::setValue( KoUnit::ptToUnit( oldvalue, unit ) ); m_unit = unit; setSuffix( KoUnit::unitName( unit ).prepend( ' ' ) ); } double KoUnitDoubleSpinBox::value( void ) const { return KoUnit::fromUserValue( KDoubleSpinBox::value(), m_unit ); } void KoUnitDoubleSpinBox::setMinValue( double min ) { m_lowerInPoints = min; KDoubleSpinBox::setMinValue( KoUnit::toUserValue( m_lowerInPoints, m_unit ) ); } void KoUnitDoubleSpinBox::setMaxValue( double max ) { m_upperInPoints = max; KDoubleSpinBox::setMaxValue( KoUnit::toUserValue( m_upperInPoints, m_unit ) ); } void KoUnitDoubleSpinBox::setLineStep( double step ) { m_stepInPoints = KoUnit::toUserValue(step, KoUnit::U_PT ); KDoubleSpinBox::setLineStep( step ); } void KoUnitDoubleSpinBox::setLineStepPt( double step ) { m_stepInPoints = step; KDoubleSpinBox::setLineStep( KoUnit::toUserValue( m_stepInPoints, m_unit ) ); } void KoUnitDoubleSpinBox::setMinMaxStep( double min, double max, double step ) { setMinValue( min ); setMaxValue( max ); setLineStepPt( step ); } // ---------------------------------------------------------------- KoUnitDoubleLineEdit::KoUnitDoubleLineEdit( TQWidget *parent, const char *name ) : KLineEdit( parent, name ), KoUnitDoubleBase( KoUnit::U_PT, 2 ), m_value( 0.0 ), m_lower( 0.0 ), m_upper( 9999.99 ), m_lowerInPoints( 0.0 ), m_upperInPoints( 9999.99 ) { setAlignment( TQt::AlignRight ); m_validator = new KoUnitDoubleValidator( this, this ); setValidator( m_validator ); setUnit( KoUnit::U_PT ); changeValue( KoUnit::ptToUnit( 0.0, KoUnit::U_PT ) ); } KoUnitDoubleLineEdit::KoUnitDoubleLineEdit( TQWidget *parent, double lower, double upper, double value, KoUnit::Unit unit, unsigned int precision, const char *name ) : KLineEdit( parent, name ), KoUnitDoubleBase( unit, precision ), m_value( value ), m_lower( lower ), m_upper( upper ), m_lowerInPoints( lower ), m_upperInPoints( upper ) { setAlignment( TQt::AlignRight ); m_validator = new KoUnitDoubleValidator( this, this ); setValidator( m_validator ); setUnit( unit ); changeValue( KoUnit::ptToUnit( value, unit ) ); } void KoUnitDoubleLineEdit::changeValue( double value ) { m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value ); setText( getVisibleText( m_value ) ); } void KoUnitDoubleLineEdit::setUnit( KoUnit::Unit unit ) { KoUnit::Unit old = m_unit; m_unit = unit; m_lower = KoUnit::ptToUnit( m_lowerInPoints, unit ); m_upper = KoUnit::ptToUnit( m_upperInPoints, unit ); changeValue( KoUnit::ptToUnit( KoUnit::fromUserValue( m_value, old ), unit ) ); } bool KoUnitDoubleLineEdit::eventFilter( TQObject* o, TQEvent* ev ) { #if 0 if( ev->type() == TQEvent::FocusOut || ev->type() == TQEvent::Leave || ev->type() == TQEvent::Hide ) { bool ok; double value = toDouble( text(), &ok ); changeValue( value ); return false; } else #endif return TQLineEdit::eventFilter( o, ev ); } double KoUnitDoubleLineEdit::value( void ) const { return KoUnit::fromUserValue( m_value, m_unit ); } // ---------------------------------------------------------------- KoUnitDoubleComboBox::KoUnitDoubleComboBox( TQWidget *parent, const char *name ) : KComboBox( true, parent, name ), KoUnitDoubleBase( KoUnit::U_PT, 2 ), m_value( 0.0 ), m_lower( 0.0 ), m_upper( 9999.99 ), m_lowerInPoints( 0.0 ), m_upperInPoints( 9999.99 ) { lineEdit()->setAlignment( TQt::AlignRight ); m_validator = new KoUnitDoubleValidator( this, this ); lineEdit()->setValidator( m_validator ); setUnit( KoUnit::U_PT ); changeValue( KoUnit::ptToUnit( 0.0, KoUnit::U_PT ) ); connect( this, TQT_SIGNAL( activated( int ) ), this, TQT_SLOT( slotActivated( int ) ) ); } KoUnitDoubleComboBox::KoUnitDoubleComboBox( TQWidget *parent, double lower, double upper, double value, KoUnit::Unit unit, unsigned int precision, const char *name ) : KComboBox( true, parent, name ), KoUnitDoubleBase( unit, precision ), m_value( value ), m_lower( lower ), m_upper( upper ), m_lowerInPoints( lower ), m_upperInPoints( upper ) { lineEdit()->setAlignment( TQt::AlignRight ); m_validator = new KoUnitDoubleValidator( this, this ); lineEdit()->setValidator( m_validator ); setUnit( unit ); changeValue( KoUnit::ptToUnit( value, unit ) ); connect( this, TQT_SIGNAL( activated( int ) ), this, TQT_SLOT( slotActivated( int ) ) ); } void KoUnitDoubleComboBox::changeValue( double value ) { TQString oldLabel = lineEdit()->text(); updateValue( value ); if( lineEdit()->text() != oldLabel ) emit valueChanged( m_value ); } void KoUnitDoubleComboBox::updateValue( double value ) { m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value ); lineEdit()->setText( getVisibleText( m_value ) ); } void KoUnitDoubleComboBox::insertItem( double value, int index ) { KComboBox::insertItem( getVisibleText( value ), index ); } void KoUnitDoubleComboBox::slotActivated( int index ) { double oldvalue = m_value; bool ok; double value = toDouble( text( index ), &ok ); m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value ); if( m_value != oldvalue ) emit valueChanged( m_value ); } void KoUnitDoubleComboBox::setUnit( KoUnit::Unit unit ) { KoUnit::Unit old = m_unit; m_unit = unit; m_lower = KoUnit::ptToUnit( m_lowerInPoints, unit ); m_upper = KoUnit::ptToUnit( m_upperInPoints, unit ); changeValue( KoUnit::ptToUnit( KoUnit::fromUserValue( m_value, old ), unit ) ); } bool KoUnitDoubleComboBox::eventFilter( TQObject* o, TQEvent* ev ) { #if 0 if( ev->type() == TQEvent::FocusOut || ev->type() == TQEvent::Leave || ev->type() == TQEvent::Hide ) { bool ok; double value = toDouble( lineEdit()->text(), &ok ); changeValue( value ); return false; } else #endif return TQComboBox::eventFilter( o, ev ); } double KoUnitDoubleComboBox::value( void ) const { return KoUnit::fromUserValue( m_value, m_unit ); } // ---------------------------------------------------------------- KoUnitDoubleSpinComboBox::KoUnitDoubleSpinComboBox( TQWidget *parent, const char *name ) : TQWidget( parent ), m_step( 1.0 ) { TQGridLayout *tqlayout = new TQGridLayout( this, 2, 3 ); //tqlayout->setMargin( 2 ); TQPushButton *up = new TQPushButton( "+", this ); //up->setFlat( true ); up->setMaximumHeight( 15 ); up->setMaximumWidth( 15 ); tqlayout->addWidget( up, 0, 0 ); connect( up, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotUpClicked() ) ); TQPushButton *down = new TQPushButton( "-", this ); down->setMaximumHeight( 15 ); down->setMaximumWidth( 15 ); tqlayout->addWidget( down, 1, 0 ); connect( down, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotDownClicked() ) ); m_combo = new KoUnitDoubleComboBox( this, KoUnit::ptToUnit( 0.0, KoUnit::U_PT ), KoUnit::ptToUnit( 9999.99, KoUnit::U_PT ), 0.0, KoUnit::U_PT, 2, name ); connect( m_combo, TQT_SIGNAL( valueChanged( double ) ), this, TQT_SIGNAL( valueChanged( double ) ) ); tqlayout->addMultiCellWidget( m_combo, 0, 1, 2, 2 ); } KoUnitDoubleSpinComboBox::KoUnitDoubleSpinComboBox( TQWidget *parent, double lower, double upper, double step, double value, KoUnit::Unit unit, unsigned int precision, const char *name ) : TQWidget( parent ), m_step( step )//, m_lowerInPoints( lower ), m_upperInPoints( upper ) { TQGridLayout *tqlayout = new TQGridLayout( this, 2, 3 ); //tqlayout->setMargin( 2 ); TQPushButton *up = new TQPushButton( "+", this ); //up->setFlat( true ); up->setMaximumHeight( 15 ); up->setMaximumWidth( 15 ); tqlayout->addWidget( up, 0, 0 ); connect( up, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotUpClicked() ) ); TQPushButton *down = new TQPushButton( "-", this ); down->setMaximumHeight( 15 ); down->setMaximumWidth( 15 ); tqlayout->addWidget( down, 1, 0 ); connect( down, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotDownClicked() ) ); m_combo = new KoUnitDoubleComboBox( this, KoUnit::ptToUnit( lower, unit ), KoUnit::ptToUnit( upper, unit ), value, unit, precision, name ); connect( m_combo, TQT_SIGNAL( valueChanged( double ) ), this, TQT_SIGNAL( valueChanged( double ) ) ); tqlayout->addMultiCellWidget( m_combo, 0, 1, 2, 2 ); } void KoUnitDoubleSpinComboBox::slotUpClicked() { m_combo->changeValue( m_combo->value() + m_step ); } void KoUnitDoubleSpinComboBox::slotDownClicked() { m_combo->changeValue( m_combo->value() - m_step ); } void KoUnitDoubleSpinComboBox::insertItem( double value, int index ) { m_combo->insertItem( value, index ); } void KoUnitDoubleSpinComboBox::updateValue( double value ) { m_combo->updateValue( value ); } double KoUnitDoubleSpinComboBox::value() const { return m_combo->value(); }