KoUnitWidgets.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002, Rob Buis(buis@kde.org)
3 Copyright (C) 2004, Nicolas GOUTTE <goutte@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include "KoUnitWidgets.h"
22#include "KoUnitWidgets.moc"
23#include <kdebug.h>
24#include <tdeglobal.h>
25#include <tdelocale.h>
26#include <tqpushbutton.h>
27#include <tqlayout.h>
28
29
30// ----------------------------------------------------------------
31// Support classes
32
33
34KoUnitDoubleValidator::KoUnitDoubleValidator( KoUnitDoubleBase *base, TQObject *parent, const char *name )
35: KDoubleValidator( parent, name ), m_base( base )
36{
37}
38
39TQValidator::State
40KoUnitDoubleValidator::validate( TQString &s, int &pos ) const
41{
42
43 kdDebug(30004) << "KoUnitDoubleValidator::validate : " << s << " at " << pos << endl;
44 TQValidator::State result = Acceptable;
45
46 TQRegExp regexp ("([ a-zA-Z]+)$"); // Letters or spaces at end
47 const int res = regexp.search( s );
48
49 if ( res == -1 )
50 {
51 // Nothing like an unit? The user is probably editing the unit
52 kdDebug(30004) << "Intermediate (no unit)" << endl;
53 return Intermediate;
54 }
55
56 // ### TODO: are all the TQString::stripWhiteSpace really necessary?
57 const TQString number ( s.left( res ).stripWhiteSpace() );
58 const TQString unitName ( regexp.cap( 1 ).stripWhiteSpace().lower() );
59
60 kdDebug(30004) << "Split:" << number << ":" << unitName << ":" << endl;
61
62 bool ok = false;
63 const double value = m_base->toDouble( number, &ok );
64 double newVal = 0.0;
65 if( ok )
66 {
67 KoUnit::Unit unit = KoUnit::unit( unitName, &ok );
68 if ( ok )
69 newVal = KoUnit::fromUserValue( value, unit );
70 else
71 {
72 // Probably the user is trying to edit the unit
73 kdDebug(30004) << "Intermediate (unknown unit)" << endl;
74 return Intermediate;
75 }
76 }
77 else
78 {
79 kdWarning(30004) << "Not a number: " << number << endl;
80 return Invalid;
81 }
82
83 newVal = KoUnit::ptToUnit( newVal, m_base->m_unit );
84
85 s = m_base->getVisibleText( newVal );
86
87 return result;
88}
89
90
91TQString KoUnitDoubleBase::getVisibleText( double value ) const
92{
93 const TQString num ( TQString( "%1%2").arg( TDEGlobal::locale()->formatNumber( value, m_precision ), KoUnit::unitName( m_unit ) ) );
94 kdDebug(30004) << "getVisibleText: " << TQString::number( value, 'f', 12 ) << " => " << num << endl;
95 return num;
96}
97
98double KoUnitDoubleBase::toDouble( const TQString& str, bool* ok ) const
99{
100 TQString str2( str );
101 /* TDELocale::readNumber wants the thousand separator exactly at 1000.
102 But when editing, it might be anywhere. So we need to remove it. */
103 const TQString sep( TDEGlobal::locale()->thousandsSeparator() );
104 if ( !sep.isEmpty() )
105 str2.remove( sep );
106 str2.remove( KoUnit::unitName( m_unit ) );
107 const double dbl = TDEGlobal::locale()->readNumber( str2, ok );
108 if ( ok )
109 kdDebug(30004) << "toDouble:" << str << ": => :" << str2 << ": => " << TQString::number( dbl, 'f', 12 ) << endl;
110 else
111 kdWarning(30004) << "toDouble error:" << str << ": => :" << str2 << ":" << endl;
112 return dbl;
113}
114
115
116// ----------------------------------------------------------------
117// Widget classes
118
119
120KoUnitDoubleSpinBox::KoUnitDoubleSpinBox( TQWidget *parent, const char *name )
121 : KDoubleSpinBox( parent, name ), KoUnitDoubleBase( KoUnit::U_PT, 2 )
122 , m_lowerInPoints( -9999 )
123 , m_upperInPoints( 9999 )
124 , m_stepInPoints( 1 )
125{
127 m_validator = new KoUnitDoubleValidator( this, this );
128 TQSpinBox::setValidator( m_validator );
129 setAcceptLocalizedNumbers( true );
130 setUnit( KoUnit::U_PT );
131
132 connect(this, TQ_SIGNAL(valueChanged( double )), TQ_SLOT(privateValueChanged()));
133}
134
135
136KoUnitDoubleSpinBox::KoUnitDoubleSpinBox( TQWidget *parent,
137 double lower, double upper,
138 double step,
139 double value,
140 KoUnit::Unit unit,
141 unsigned int precision,
142 const char *name )
143 : KDoubleSpinBox( lower, upper, step, value, precision, parent, name ),
144 KoUnitDoubleBase( unit, precision ),
145 m_lowerInPoints( lower ), m_upperInPoints( upper ), m_stepInPoints( step )
146{
147 m_unit = KoUnit::U_PT;
148 m_validator = new KoUnitDoubleValidator( this, this );
149 TQSpinBox::setValidator( m_validator );
150 setAcceptLocalizedNumbers( true );
151 setUnit( unit );
152 changeValue( value );
153 setLineStep( 0.5 );
154
155 connect(this, TQ_SIGNAL(valueChanged( double )), TQ_SLOT(privateValueChanged()));
156}
157
158void
159KoUnitDoubleSpinBox::changeValue( double val )
160{
162 // TODO: emit valueChanged ONLY if the value was out-of-bounds
163 // This will allow the 'user' dialog to set a dirty bool and ensure
164 // a proper value is getting saved.
165}
166
167void KoUnitDoubleSpinBox::privateValueChanged() {
168 emit valueChangedPt( value () );
169}
170
171void
172KoUnitDoubleSpinBox::setUnit( KoUnit::Unit unit )
173{
174 double oldvalue = KoUnit::fromUserValue( KDoubleSpinBox::value(), m_unit );
175 KDoubleSpinBox::setMinValue( KoUnit::toUserValue( m_lowerInPoints, unit ) );
176 KDoubleSpinBox::setMaxValue( KoUnit::toUserValue( m_upperInPoints, unit ) );
177 KDoubleSpinBox::setLineStep( KoUnit::toUserValue( m_stepInPoints, unit ) );
178 KDoubleSpinBox::setValue( KoUnit::ptToUnit( oldvalue, unit ) );
179 m_unit = unit;
180 setSuffix( KoUnit::unitName( unit ).prepend( ' ' ) );
181}
182
183double KoUnitDoubleSpinBox::value( void ) const
184{
186}
187
189{
190 m_lowerInPoints = min;
191 KDoubleSpinBox::setMinValue( KoUnit::toUserValue( m_lowerInPoints, m_unit ) );
192}
193
195{
196 m_upperInPoints = max;
197 KDoubleSpinBox::setMaxValue( KoUnit::toUserValue( m_upperInPoints, m_unit ) );
198}
199
201{
202 m_stepInPoints = KoUnit::toUserValue(step, KoUnit::U_PT );
204}
205
207{
208 m_stepInPoints = step;
209 KDoubleSpinBox::setLineStep( KoUnit::toUserValue( m_stepInPoints, m_unit ) );
210}
211
212void KoUnitDoubleSpinBox::setMinMaxStep( double min, double max, double step )
213{
214 setMinValue( min );
215 setMaxValue( max );
216 setLineStepPt( step );
217}
218
219// ----------------------------------------------------------------
220
221
222KoUnitDoubleLineEdit::KoUnitDoubleLineEdit( TQWidget *parent, const char *name )
223 : KLineEdit( parent, name ), KoUnitDoubleBase( KoUnit::U_PT, 2 ), m_value( 0.0 ), m_lower( 0.0 ), m_upper( 9999.99 ),
224 m_lowerInPoints( 0.0 ), m_upperInPoints( 9999.99 )
225{
226 setAlignment( TQt::AlignRight );
227 m_validator = new KoUnitDoubleValidator( this, this );
228 setValidator( m_validator );
229 setUnit( KoUnit::U_PT );
230 changeValue( KoUnit::ptToUnit( 0.0, KoUnit::U_PT ) );
231}
232
233KoUnitDoubleLineEdit::KoUnitDoubleLineEdit( TQWidget *parent, double lower, double upper, double value, KoUnit::Unit unit,
234 unsigned int precision, const char *name )
235 : KLineEdit( parent, name ), KoUnitDoubleBase( unit, precision ), m_value( value ), m_lower( lower ), m_upper( upper ),
236 m_lowerInPoints( lower ), m_upperInPoints( upper )
237{
238 setAlignment( TQt::AlignRight );
239 m_validator = new KoUnitDoubleValidator( this, this );
240 setValidator( m_validator );
241 setUnit( unit );
242 changeValue( KoUnit::ptToUnit( value, unit ) );
243}
244
245void
246KoUnitDoubleLineEdit::changeValue( double value )
247{
248 m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value );
249 setText( getVisibleText( m_value ) );
250}
251
252void
253KoUnitDoubleLineEdit::setUnit( KoUnit::Unit unit )
254{
255 KoUnit::Unit old = m_unit;
256 m_unit = unit;
257 m_lower = KoUnit::ptToUnit( m_lowerInPoints, unit );
258 m_upper = KoUnit::ptToUnit( m_upperInPoints, unit );
259 changeValue( KoUnit::ptToUnit( KoUnit::fromUserValue( m_value, old ), unit ) );
260}
261
262bool
263KoUnitDoubleLineEdit::eventFilter( TQObject* o, TQEvent* ev )
264{
265#if 0
266 if( ev->type() == TQEvent::FocusOut || ev->type() == TQEvent::Leave || ev->type() == TQEvent::Hide )
267 {
268 bool ok;
269 double value = toDouble( text(), &ok );
270 changeValue( value );
271 return false;
272 }
273 else
274#endif
275 return TQLineEdit::eventFilter( o, ev );
276}
277
278double KoUnitDoubleLineEdit::value( void ) const
279{
280 return KoUnit::fromUserValue( m_value, m_unit );
281}
282
283
284// ----------------------------------------------------------------
285
286
287KoUnitDoubleComboBox::KoUnitDoubleComboBox( TQWidget *parent, const char *name )
288 : 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 )
289{
290 lineEdit()->setAlignment( TQt::AlignRight );
291 m_validator = new KoUnitDoubleValidator( this, this );
292 lineEdit()->setValidator( m_validator );
293 setUnit( KoUnit::U_PT );
294 changeValue( KoUnit::ptToUnit( 0.0, KoUnit::U_PT ) );
295 connect( this, TQ_SIGNAL( activated( int ) ), this, TQ_SLOT( slotActivated( int ) ) );
296}
297
298KoUnitDoubleComboBox::KoUnitDoubleComboBox( TQWidget *parent, double lower, double upper, double value, KoUnit::Unit unit,
299 unsigned int precision, const char *name )
300 : KComboBox( true, parent, name ), KoUnitDoubleBase( unit, precision ), m_value( value ), m_lower( lower ), m_upper( upper ),
301 m_lowerInPoints( lower ), m_upperInPoints( upper )
302{
303 lineEdit()->setAlignment( TQt::AlignRight );
304 m_validator = new KoUnitDoubleValidator( this, this );
305 lineEdit()->setValidator( m_validator );
306 setUnit( unit );
307 changeValue( KoUnit::ptToUnit( value, unit ) );
308 connect( this, TQ_SIGNAL( activated( int ) ), this, TQ_SLOT( slotActivated( int ) ) );
309}
310
311void
312KoUnitDoubleComboBox::changeValue( double value )
313{
314 TQString oldLabel = lineEdit()->text();
315 updateValue( value );
316 if( lineEdit()->text() != oldLabel )
317 emit valueChanged( m_value );
318}
319
320void
321KoUnitDoubleComboBox::updateValue( double value )
322{
323 m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value );
324 lineEdit()->setText( getVisibleText( m_value ) );
325}
326
327void
328KoUnitDoubleComboBox::insertItem( double value, int index )
329{
330 KComboBox::insertItem( getVisibleText( value ), index );
331}
332
333void
334KoUnitDoubleComboBox::slotActivated( int index )
335{
336 double oldvalue = m_value;
337 bool ok;
338 double value = toDouble( text( index ), &ok );
339 m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value );
340 if( m_value != oldvalue )
341 emit valueChanged( m_value );
342}
343
344void
345KoUnitDoubleComboBox::setUnit( KoUnit::Unit unit )
346{
347 KoUnit::Unit old = m_unit;
348 m_unit = unit;
349 m_lower = KoUnit::ptToUnit( m_lowerInPoints, unit );
350 m_upper = KoUnit::ptToUnit( m_upperInPoints, unit );
351 changeValue( KoUnit::ptToUnit( KoUnit::fromUserValue( m_value, old ), unit ) );
352}
353
354bool
355KoUnitDoubleComboBox::eventFilter( TQObject* o, TQEvent* ev )
356{
357#if 0
358 if( ev->type() == TQEvent::FocusOut || ev->type() == TQEvent::Leave || ev->type() == TQEvent::Hide )
359 {
360 bool ok;
361 double value = toDouble( lineEdit()->text(), &ok );
362 changeValue( value );
363 return false;
364 }
365 else
366#endif
367 return TQComboBox::eventFilter( o, ev );
368}
369
370double KoUnitDoubleComboBox::value( void ) const
371{
372 return KoUnit::fromUserValue( m_value, m_unit );
373}
374
375
376// ----------------------------------------------------------------
377
378
379KoUnitDoubleSpinComboBox::KoUnitDoubleSpinComboBox( TQWidget *parent, const char *name )
380 : TQWidget( parent ), m_step( 1.0 )
381{
382 TQGridLayout *layout = new TQGridLayout( this, 2, 3 );
383 //layout->setMargin( 2 );
384 TQPushButton *up = new TQPushButton( "+", this );
385 //up->setFlat( true );
386 up->setMaximumHeight( 15 );
387 up->setMaximumWidth( 15 );
388 layout->addWidget( up, 0, 0 );
389 connect( up, TQ_SIGNAL( clicked() ), this, TQ_SLOT( slotUpClicked() ) );
390
391 TQPushButton *down = new TQPushButton( "-", this );
392 down->setMaximumHeight( 15 );
393 down->setMaximumWidth( 15 );
394 layout->addWidget( down, 1, 0 );
395 connect( down, TQ_SIGNAL( clicked() ), this, TQ_SLOT( slotDownClicked() ) );
396
397 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 );
398 connect( m_combo, TQ_SIGNAL( valueChanged( double ) ), this, TQ_SIGNAL( valueChanged( double ) ) );
399 layout->addMultiCellWidget( m_combo, 0, 1, 2, 2 );
400}
401
402KoUnitDoubleSpinComboBox::KoUnitDoubleSpinComboBox( TQWidget *parent, double lower, double upper, double step, double value,
403 KoUnit::Unit unit, unsigned int precision, const char *name )
404 : TQWidget( parent ), m_step( step )//, m_lowerInPoints( lower ), m_upperInPoints( upper )
405{
406 TQGridLayout *layout = new TQGridLayout( this, 2, 3 );
407 //layout->setMargin( 2 );
408 TQPushButton *up = new TQPushButton( "+", this );
409 //up->setFlat( true );
410 up->setMaximumHeight( 15 );
411 up->setMaximumWidth( 15 );
412 layout->addWidget( up, 0, 0 );
413 connect( up, TQ_SIGNAL( clicked() ), this, TQ_SLOT( slotUpClicked() ) );
414
415 TQPushButton *down = new TQPushButton( "-", this );
416 down->setMaximumHeight( 15 );
417 down->setMaximumWidth( 15 );
418 layout->addWidget( down, 1, 0 );
419 connect( down, TQ_SIGNAL( clicked() ), this, TQ_SLOT( slotDownClicked() ) );
420
421 m_combo = new KoUnitDoubleComboBox( this, KoUnit::ptToUnit( lower, unit ), KoUnit::ptToUnit( upper, unit ), value, unit, precision, name );
422 connect( m_combo, TQ_SIGNAL( valueChanged( double ) ), this, TQ_SIGNAL( valueChanged( double ) ) );
423 layout->addMultiCellWidget( m_combo, 0, 1, 2, 2 );
424}
425
426void
427KoUnitDoubleSpinComboBox::slotUpClicked()
428{
429 m_combo->changeValue( m_combo->value() + m_step );
430}
431
432void
433KoUnitDoubleSpinComboBox::slotDownClicked()
434{
435 m_combo->changeValue( m_combo->value() - m_step );
436}
437
438void
439KoUnitDoubleSpinComboBox::insertItem( double value, int index )
440{
441 m_combo->insertItem( value, index );
442}
443
444void
445KoUnitDoubleSpinComboBox::updateValue( double value )
446{
447 m_combo->updateValue( value );
448}
449
450double
452{
453 return m_combo->value();
454}
455
void setPrecision(int precision)
void setValidator(const TQValidator *)
virtual void setValue(double value)
void setMaxValue(double value)
void setMinValue(double value)
void setLineStep(double step)
double value() const
virtual void setText(const TQString &)
Base for the unit widgets.
TQString getVisibleText(double value) const
Transform the double in a nice text, using locale symbols.
double toDouble(const TQString &str, bool *ok) const
Transfrom a string into a double, while taking care of locale specific symbols.
Combo box for double precision numbers with unit display.
double m_upperInPoints
highest value in points
double m_lowerInPoints
lowest value in points
double value(void) const
double value(void) const
void valueChangedPt(double)
emitted like valueChanged in the parent, but this one emits the point value
void setMinValue(double min)
Set minimum value in points.
void setLineStep(double step)
Set step size in the current unit.
void setMaxValue(double max)
Set maximum value in points.
void setMinMaxStep(double min, double max, double step)
Set minimum, maximum value and the step size (all in points) (by Tymoteusz Majewski,...
double value(void) const
void setLineStepPt(double step)
Set step size in points.
double value(void) const
Validator for the unit widget classes.
KOffice stores everything in pt (using "double") internally.
Definition KoUnit.h:60
static double toUserValue(double ptValue, Unit unit)
This method is the one to use to display a value in a dialog.
Definition KoUnit.cpp:68
static double fromUserValue(double value, Unit unit)
This method is the one to use to read a value from a dialog.
Definition KoUnit.cpp:120
static double ptToUnit(const double ptValue, const Unit unit)
Convert the value ptValue to a given unit unit Unlike KoUnit::ptToUnit the return value remains unrou...
Definition KoUnit.cpp:91
Unit
Length units supported by KOffice.
Definition KoUnit.h:63
static Unit unit(const TQString &_unitName, bool *ok=0)
Convert a unit name into a Unit enum.
Definition KoUnit.cpp:182
static TQString unitName(Unit _unit)
Get the name of a unit.
Definition KoUnit.cpp:200
TDEAction * up(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
const char * name(StdAction id)
@ Invalid
invalid property type
Definition property.h:68