1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include <comphelper/processfactory.hxx>
23 #include <comphelper/string.hxx>
25 #include "tools/debug.hxx"
29 #include <vcl/dialog.hxx>
30 #include <vcl/field.hxx>
31 #include <vcl/event.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/settings.hxx>
38 #include "i18nutil/unicode.hxx"
40 #include "rtl/math.hxx"
42 #include <unotools/localedatawrapper.hxx>
44 using namespace ::com::sun::star
;
45 using namespace ::comphelper
;
50 #define FORMAT_NUMERIC 1
51 #define FORMAT_METRIC 2
52 #define FORMAT_CURRENCY 3
54 sal_Int64
ImplPower10( sal_uInt16 n
)
59 for ( i
=0; i
< n
; i
++ )
65 bool ImplNumericProcessKeyInput( Edit
*, const KeyEvent
& rKEvt
,
66 bool bStrictFormat
, bool bThousandSep
,
67 const LocaleDataWrapper
& rLocaleDataWrappper
)
73 sal_Unicode cChar
= rKEvt
.GetCharCode();
74 sal_uInt16 nGroup
= rKEvt
.GetKeyCode().GetGroup();
76 if ( (nGroup
== KEYGROUP_FKEYS
) || (nGroup
== KEYGROUP_CURSOR
) ||
77 (nGroup
== KEYGROUP_MISC
) ||
78 ((cChar
>= '0') && (cChar
<= '9')) ||
79 string::equals(rLocaleDataWrappper
.getNumDecimalSep(), cChar
) ||
80 (bThousandSep
&& string::equals(rLocaleDataWrappper
.getNumThousandSep(), cChar
)) ||
88 bool ImplNumericGetValue( const OUString
& rStr
, sal_Int64
& rValue
,
89 sal_uInt16 nDecDigits
, const LocaleDataWrapper
& rLocaleDataWrappper
,
90 bool bCurrency
= false )
93 OUStringBuffer aStr1
, aStr2
, aStrFrac
, aStrNum
, aStrDenom
;
94 bool bNegative
= false;
96 sal_Int32 nDecPos
, nFracDivPos
, nFracNumPos
;
99 // react on empty string
100 if ( rStr
.isEmpty() )
103 // remove leading and trailing spaces
107 // find position of decimal point
108 nDecPos
= aStr
.indexOf( rLocaleDataWrappper
.getNumDecimalSep() );
109 // find position of fraction
110 nFracDivPos
= aStr
.indexOf( '/' );
112 // parse fractional strings
116 nFracNumPos
= aStr
.lastIndexOf(' ', nFracDivPos
);
118 // If in "a b/c" format.
119 if(nFracNumPos
!= -1 )
121 aStr1
.append(aStr
.getStr(), nFracNumPos
);
122 aStrNum
.append(aStr
.getStr()+nFracNumPos
+1, nFracDivPos
-nFracNumPos
-1);
123 aStrDenom
.append(aStr
.getStr()+nFracDivPos
+1);
125 // "a/b" format, or not a fraction at all
128 aStrNum
.append(aStr
.getStr(), nFracDivPos
);
129 aStrDenom
.append(aStr
.getStr()+nFracDivPos
+1);
133 // parse decimal strings
134 else if ( nDecPos
>= 0)
136 aStr1
.append(aStr
.getStr(), nDecPos
);
137 aStr2
.append(aStr
.getStr()+nDecPos
+1);
145 if ( aStr
.startsWith("(") && aStr
.endsWith(")") )
149 for (sal_Int32 i
=0; i
< aStr
.getLength(); i
++ )
151 if ( (aStr
[i
] >= '0') && (aStr
[i
] <= '9') )
153 else if ( aStr
[i
] == '-' )
160 if ( !bNegative
&& bCurrency
&& !aStr
.isEmpty() )
162 sal_uInt16 nFormat
= rLocaleDataWrappper
.getCurrNegativeFormat();
163 if ( (nFormat
== 3) || (nFormat
== 6) || // $1- || 1-$
164 (nFormat
== 7) || (nFormat
== 10) ) // 1$- || 1 $-
166 for (sal_Int32 i
= aStr
.getLength()-1; i
> 0; --i
)
168 if ( (aStr
[i
] >= '0') && (aStr
[i
] <= '9') )
170 else if ( aStr
[i
] == '-' )
181 if ( !aStr1
.isEmpty() && aStr1
[0] == '-')
183 if ( !aStrNum
.isEmpty() && aStrNum
[0] == '-') // For non-mixed fractions
187 // remove all unwanted charaters
189 for (sal_Int32 i
=0; i
< aStr1
.getLength(); )
191 if ( (aStr1
[i
] >= '0') && (aStr1
[i
] <= '9') )
194 aStr1
.remove( i
, 1 );
198 for (sal_Int32 i
=0; i
< aStr2
.getLength(); )
200 if ((aStr2
[i
] >= '0') && (aStr2
[i
] <= '9'))
208 for (sal_Int32 i
=0; i
< aStrNum
.getLength(); )
210 if ((aStrNum
[i
] >= '0') && (aStrNum
[i
] <= '9'))
213 aStrNum
.remove(i
, 1);
216 for (sal_Int32 i
=0; i
< aStrDenom
.getLength(); )
218 if ((aStrDenom
[i
] >= '0') && (aStrDenom
[i
] <= '9'))
221 aStrDenom
.remove(i
, 1);
226 if ( !bFrac
&& aStr1
.isEmpty() && aStr2
.isEmpty() )
228 else if ( bFrac
&& aStr1
.isEmpty() && (aStrNum
.isEmpty() || aStrDenom
.isEmpty()) )
231 if ( aStr1
.isEmpty() )
234 aStr1
.insert(0, "-");
236 // Convert fractional strings
238 // Convert to fraction
239 sal_Int64 nWholeNum
= aStr1
.makeStringAndClear().toInt64();
240 sal_Int64 nNum
= aStrNum
.makeStringAndClear().toInt64();
241 sal_Int64 nDenom
= aStrDenom
.makeStringAndClear().toInt64();
242 if (nDenom
== 0) return false; // Division by zero
243 double nFrac2Dec
= nWholeNum
+ (double)nNum
/nDenom
; // Convert to double for floating point precision
244 aStrFrac
.append(nFrac2Dec
);
245 // Reconvert division result to string and parse
246 nDecPos
= aStrFrac
.indexOf( rLocaleDataWrappper
.getNumDecimalSep() );
249 aStr1
.append(aStrFrac
.getStr(), nDecPos
);
250 aStr2
.append(aStrFrac
.getStr()+nDecPos
+1);
256 // prune and round fraction
258 if (aStr2
.getLength() > nDecDigits
)
260 if (aStr2
[nDecDigits
] >= '5')
262 string::truncateToLength(aStr2
, nDecDigits
);
264 if (aStr2
.getLength() < nDecDigits
)
265 string::padToLength(aStr2
, nDecDigits
, '0');
267 aStr
= aStr1
.makeStringAndClear() + aStr2
.makeStringAndClear();
270 nValue
= aStr
.toInt64();
273 // check if string is equivalent to zero
274 sal_Int16 nIndex
= bNegative
? 1 : 0;
275 while (nIndex
< aStr
.getLength() && aStr
[nIndex
] == '0')
277 if( nIndex
< aStr
.getLength() )
279 rValue
= bNegative
? SAL_MIN_INT64
: SAL_MAX_INT64
;
296 void ImplUpdateSeparatorString( OUString
& io_rText
,
297 const OUString
& rOldDecSep
, const OUString
& rNewDecSep
,
298 const OUString
& rOldThSep
, const OUString
& rNewThSep
)
300 OUStringBuffer
aBuf( io_rText
.getLength() );
301 sal_Int32 nIndexDec
= 0, nIndexTh
= 0, nIndex
= 0;
303 const sal_Unicode
* pBuffer
= io_rText
.getStr();
304 while( nIndex
!= -1 )
306 nIndexDec
= io_rText
.indexOf( rOldDecSep
, nIndex
);
307 nIndexTh
= io_rText
.indexOf( rOldThSep
, nIndex
);
308 if( (nIndexTh
!= -1 && nIndexDec
!= -1 && nIndexTh
< nIndexDec
)
309 || (nIndexTh
!= -1 && nIndexDec
== -1)
312 aBuf
.append( pBuffer
+ nIndex
, nIndexTh
- nIndex
);
313 aBuf
.append( rNewThSep
);
314 nIndex
= nIndexTh
+ rOldThSep
.getLength();
316 else if( nIndexDec
!= -1 )
318 aBuf
.append( pBuffer
+ nIndex
, nIndexDec
- nIndex
);
319 aBuf
.append( rNewDecSep
);
320 nIndex
= nIndexDec
+ rOldDecSep
.getLength();
324 aBuf
.append( pBuffer
+ nIndex
);
329 io_rText
= aBuf
.makeStringAndClear();
332 void ImplUpdateSeparators( const OUString
& rOldDecSep
, const OUString
& rNewDecSep
,
333 const OUString
& rOldThSep
, const OUString
& rNewThSep
,
336 bool bChangeDec
= (rOldDecSep
!= rNewDecSep
);
337 bool bChangeTh
= (rOldThSep
!= rNewThSep
);
339 if( bChangeDec
|| bChangeTh
)
341 bool bUpdateMode
= pEdit
->IsUpdateMode();
342 pEdit
->SetUpdateMode( false );
343 OUString aText
= pEdit
->GetText();
344 ImplUpdateSeparatorString( aText
, rOldDecSep
, rNewDecSep
, rOldThSep
, rNewThSep
);
345 pEdit
->SetText( aText
);
347 ComboBox
* pCombo
= dynamic_cast<ComboBox
*>(pEdit
);
350 // update box entries
351 sal_Int32 nEntryCount
= pCombo
->GetEntryCount();
352 for ( sal_Int32 i
=0; i
< nEntryCount
; i
++ )
354 aText
= pCombo
->GetEntry( i
);
355 void* pEntryData
= pCombo
->GetEntryData( i
);
356 ImplUpdateSeparatorString( aText
, rOldDecSep
, rNewDecSep
, rOldThSep
, rNewThSep
);
357 pCombo
->RemoveEntryAt(i
);
358 pCombo
->InsertEntry( aText
, i
);
359 pCombo
->SetEntryData( i
, pEntryData
);
363 pEdit
->SetUpdateMode( bUpdateMode
);
369 FormatterBase::FormatterBase()
372 mpLocaleDataWrapper
= nullptr;
374 mbStrictFormat
= false;
375 mbEmptyFieldValue
= false;
376 mbEmptyFieldValueEnabled
= false;
377 mbDefaultLocale
= true;
380 FormatterBase::~FormatterBase()
384 LocaleDataWrapper
& FormatterBase::ImplGetLocaleDataWrapper() const
386 if ( !mpLocaleDataWrapper
)
388 const_cast<FormatterBase
*>(this)->mpLocaleDataWrapper
.reset( new LocaleDataWrapper( GetLanguageTag() ) );
390 return *mpLocaleDataWrapper
;
393 const LocaleDataWrapper
& FormatterBase::GetLocaleDataWrapper() const
395 return ImplGetLocaleDataWrapper();
398 void FormatterBase::Reformat()
402 void FormatterBase::ReformatAll()
407 void FormatterBase::SetStrictFormat( bool bStrict
)
409 if ( bStrict
!= mbStrictFormat
)
411 mbStrictFormat
= bStrict
;
412 if ( mbStrictFormat
)
417 void FormatterBase::SetLocale( const lang::Locale
& rLocale
)
419 ImplGetLocaleDataWrapper().setLanguageTag( LanguageTag( rLocale
) );
420 mbDefaultLocale
= false;
424 const lang::Locale
& FormatterBase::GetLocale() const
426 if ( !mpLocaleDataWrapper
|| mbDefaultLocale
)
429 return mpField
->GetSettings().GetLanguageTag().getLocale();
431 return Application::GetSettings().GetLanguageTag().getLocale();
434 return mpLocaleDataWrapper
->getLanguageTag().getLocale();
437 const LanguageTag
& FormatterBase::GetLanguageTag() const
439 if ( !mpLocaleDataWrapper
|| mbDefaultLocale
)
442 return mpField
->GetSettings().GetLanguageTag();
444 return Application::GetSettings().GetLanguageTag();
447 return mpLocaleDataWrapper
->getLanguageTag();
450 const AllSettings
& FormatterBase::GetFieldSettings() const
453 return mpField
->GetSettings();
455 return Application::GetSettings();
458 void FormatterBase::ImplSetText( const OUString
& rText
, Selection
* pNewSelection
)
463 mpField
->SetText( rText
, *pNewSelection
);
466 Selection aSel
= mpField
->GetSelection();
467 aSel
.Min() = aSel
.Max();
468 mpField
->SetText( rText
, aSel
);
471 MarkToBeReformatted( false );
475 void FormatterBase::SetEmptyFieldValue()
478 mpField
->SetText( OUString() );
479 mbEmptyFieldValue
= true;
482 bool FormatterBase::IsEmptyFieldValue() const
484 return (!mpField
|| mpField
->GetText().isEmpty());
487 bool NumericFormatter::ImplNumericReformat( const OUString
& rStr
, sal_Int64
& rValue
,
490 if ( !ImplNumericGetValue( rStr
, rValue
, GetDecimalDigits(), ImplGetLocaleDataWrapper() ) )
494 sal_Int64 nTempVal
= ClipAgainstMinMax(rValue
);
496 rOutStr
= CreateFieldText( nTempVal
);
501 void NumericFormatter::ImplInit()
506 mnMax
= SAL_MAX_INT32
;
507 // a "large" value substantially smaller than SAL_MAX_INT64, to avoid
508 // overflow in computations using this "dummy" value
510 mnType
= FORMAT_NUMERIC
;
511 mbThousandSep
= true;
512 mbShowTrailingZeros
= true;
513 mbWrapOnLimits
= false;
520 SetDecimalDigits( 0 );
523 NumericFormatter::NumericFormatter()
528 NumericFormatter::~NumericFormatter()
532 void NumericFormatter::SetMin( sal_Int64 nNewMin
)
535 if ( !IsEmptyFieldValue() )
539 void NumericFormatter::SetMax( sal_Int64 nNewMax
)
542 if ( !IsEmptyFieldValue() )
546 void NumericFormatter::SetUseThousandSep( bool bValue
)
548 mbThousandSep
= bValue
;
552 void NumericFormatter::SetDecimalDigits( sal_uInt16 nDigits
)
554 mnDecimalDigits
= nDigits
;
558 void NumericFormatter::SetShowTrailingZeros( bool bShowTrailingZeros
)
560 if ( mbShowTrailingZeros
!= bShowTrailingZeros
)
562 mbShowTrailingZeros
= bShowTrailingZeros
;
568 void NumericFormatter::SetValue( sal_Int64 nNewValue
)
570 SetUserValue( nNewValue
);
571 mnFieldValue
= mnLastValue
;
572 SetEmptyFieldValueData( false );
575 OUString
NumericFormatter::CreateFieldText( sal_Int64 nValue
) const
577 return OUString(ImplGetLocaleDataWrapper().getNum( nValue
, GetDecimalDigits(), IsUseThousandSep(), IsShowTrailingZeros() ));
580 void NumericFormatter::ImplSetUserValue( sal_Int64 nNewValue
, Selection
* pNewSelection
)
582 nNewValue
= ClipAgainstMinMax(nNewValue
);
583 mnLastValue
= nNewValue
;
586 ImplSetText( CreateFieldText( nNewValue
), pNewSelection
);
589 void NumericFormatter::SetUserValue( sal_Int64 nNewValue
)
591 ImplSetUserValue( nNewValue
);
594 sal_Int64
NumericFormatter::GetValue() const
599 sal_Int64 nTempValue
;
601 if ( ImplNumericGetValue( GetField()->GetText(), nTempValue
,
602 GetDecimalDigits(), ImplGetLocaleDataWrapper() ) )
604 return ClipAgainstMinMax(nTempValue
);
610 bool NumericFormatter::IsValueModified() const
612 if ( ImplGetEmptyFieldValue() )
613 return !IsEmptyFieldValue();
614 else if ( GetValue() != mnFieldValue
)
620 sal_Int64
NumericFormatter::Normalize( sal_Int64 nValue
) const
622 return (nValue
* ImplPower10( GetDecimalDigits() ) );
625 sal_Int64
NumericFormatter::Denormalize( sal_Int64 nValue
) const
627 sal_Int64 nFactor
= ImplPower10( GetDecimalDigits() );
629 if ((nValue
< ( SAL_MIN_INT64
+ nFactor
)) ||
630 (nValue
> ( SAL_MAX_INT64
- nFactor
)))
632 return ( nValue
/ nFactor
);
637 sal_Int64 nHalf
= nFactor
/ 2;
638 return ((nValue
- nHalf
) / nFactor
);
642 sal_Int64 nHalf
= nFactor
/ 2;
643 return ((nValue
+ nHalf
) / nFactor
);
647 void NumericFormatter::Reformat()
652 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
656 sal_Int64 nTemp
= mnLastValue
;
657 bool bOK
= ImplNumericReformat( GetField()->GetText(), nTemp
, aStr
);
662 if ( !aStr
.isEmpty() )
665 SetValue( mnLastValue
);
668 void NumericFormatter::FieldUp()
670 sal_Int64 nValue
= GetValue();
671 sal_Int64 nRemainder
= nValue
% mnSpinSize
;
673 nValue
= (nRemainder
== 0) ? nValue
+ mnSpinSize
: nValue
+ mnSpinSize
- nRemainder
;
675 nValue
= (nRemainder
== 0) ? nValue
+ mnSpinSize
: nValue
- nRemainder
;
677 nValue
= ClipAgainstMinMax(nValue
);
679 ImplNewFieldValue( nValue
);
682 void NumericFormatter::FieldDown()
684 sal_Int64 nValue
= GetValue();
685 sal_Int64 nRemainder
= nValue
% mnSpinSize
;
687 nValue
= (nRemainder
== 0) ? nValue
- mnSpinSize
: nValue
- nRemainder
;
689 nValue
= (nRemainder
== 0) ? nValue
- mnSpinSize
: nValue
- mnSpinSize
- nRemainder
;
691 nValue
= ClipAgainstMinMax(nValue
);
693 ImplNewFieldValue( nValue
);
696 void NumericFormatter::FieldFirst()
698 ImplNewFieldValue( mnFirst
);
701 void NumericFormatter::FieldLast()
703 ImplNewFieldValue( mnLast
);
706 void NumericFormatter::ImplNewFieldValue( sal_Int64 nNewValue
)
710 // !!! We should check why we do not validate in ImplSetUserValue() if the value was
711 // changed. This should be done there as well since otherwise the call to Modify would not
712 // be allowed. Anyway, the paths from ImplNewFieldValue, ImplSetUserValue, and ImplSetText
713 // should be checked and clearly traced (with comment) in order to find out what happens.
715 Selection aSelection
= GetField()->GetSelection();
716 aSelection
.Justify();
717 OUString aText
= GetField()->GetText();
718 // leave it as is if selected until end
719 if ( (sal_Int32
)aSelection
.Max() == aText
.getLength() )
721 if ( !aSelection
.Len() )
722 aSelection
.Min() = SELECTION_MAX
;
723 aSelection
.Max() = SELECTION_MAX
;
726 sal_Int64 nOldLastValue
= mnLastValue
;
727 ImplSetUserValue( nNewValue
, &aSelection
);
728 mnLastValue
= nOldLastValue
;
730 // Modify during Edit is only set during KeyInput
731 if ( GetField()->GetText() != aText
)
733 GetField()->SetModifyFlag();
734 GetField()->Modify();
739 sal_Int64
NumericFormatter::ClipAgainstMinMax(sal_Int64 nValue
) const
742 nValue
= mbWrapOnLimits
? ((nValue
- mnMin
) % (mnMax
+ 1)) + mnMin
744 else if (nValue
< mnMin
)
745 nValue
= mbWrapOnLimits
? ((nValue
+ mnMax
+ 1 - mnMin
) % (mnMax
+ 1)) + mnMin
750 NumericField::NumericField( vcl::Window
* pParent
, WinBits nWinStyle
) :
751 SpinField( pParent
, nWinStyle
)
757 void NumericField::dispose()
759 NumericFormatter::SetField( nullptr );
760 SpinField::dispose();
763 bool NumericField::set_property(const OString
&rKey
, const OString
&rValue
)
765 if (rKey
== "digits")
766 SetDecimalDigits(rValue
.toInt32());
767 else if (rKey
== "spin-size")
768 SetSpinSize(rValue
.toInt32());
769 else if (rKey
== "wrap")
770 mbWrapOnLimits
= toBool(rValue
);
772 return SpinField::set_property(rKey
, rValue
);
776 bool NumericField::PreNotify( NotifyEvent
& rNEvt
)
778 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
780 if ( ImplNumericProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
784 return SpinField::PreNotify( rNEvt
);
787 bool NumericField::EventNotify( NotifyEvent
& rNEvt
)
789 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
790 MarkToBeReformatted( false );
791 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
793 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
797 return SpinField::EventNotify( rNEvt
);
800 void NumericField::DataChanged( const DataChangedEvent
& rDCEvt
)
802 SpinField::DataChanged( rDCEvt
);
804 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
806 OUString sOldDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
807 OUString sOldThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
808 if ( IsDefaultLocale() )
809 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
810 OUString sNewDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
811 OUString sNewThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
812 ImplUpdateSeparators( sOldDecSep
, sNewDecSep
, sOldThSep
, sNewThSep
, this );
817 void NumericField::Modify()
819 MarkToBeReformatted( true );
823 void NumericField::Up()
829 void NumericField::Down()
835 void NumericField::First()
841 void NumericField::Last()
849 Size
calcMinimumSize(const Edit
&rSpinField
, const NumericFormatter
&rFormatter
)
854 nTextLen
= OUString::number(rFormatter
.GetMin()).getLength();
855 string::padToLength(aBuf
, nTextLen
, '9');
856 Size aMinTextSize
= rSpinField
.CalcMinimumSizeForText(
857 rFormatter
.CreateFieldText(aBuf
.makeStringAndClear().toInt64()));
859 nTextLen
= OUString::number(rFormatter
.GetMax()).getLength();
860 string::padToLength(aBuf
, nTextLen
, '9');
861 Size aMaxTextSize
= rSpinField
.CalcMinimumSizeForText(
862 rFormatter
.CreateFieldText(aBuf
.makeStringAndClear().toInt64()));
864 Size
aRet(std::max(aMinTextSize
.Width(), aMaxTextSize
.Width()),
865 std::max(aMinTextSize
.Height(), aMaxTextSize
.Height()));
867 OUStringBuffer
sBuf("999999999");
868 sal_uInt16 nDigits
= rFormatter
.GetDecimalDigits();
872 string::padToLength(aBuf
, aBuf
.getLength() + nDigits
, '9');
874 aMaxTextSize
= rSpinField
.CalcMinimumSizeForText(sBuf
.makeStringAndClear());
875 aRet
.Width() = std::min(aRet
.Width(), aMaxTextSize
.Width());
881 Size
NumericField::CalcMinimumSize() const
883 return calcMinimumSize(*this, *this);
886 NumericBox::NumericBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
887 ComboBox( pParent
, nWinStyle
)
891 if ( !(nWinStyle
& WB_HIDE
) )
895 void NumericBox::dispose()
897 NumericFormatter::SetField( nullptr );
901 Size
NumericBox::CalcMinimumSize() const
903 Size
aRet(calcMinimumSize(*this, *this));
907 Size
aComboSugg(ComboBox::CalcMinimumSize());
908 aRet
.Width() = std::max(aRet
.Width(), aComboSugg
.Width());
909 aRet
.Height() = std::max(aRet
.Height(), aComboSugg
.Height());
915 bool NumericBox::PreNotify( NotifyEvent
& rNEvt
)
917 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
919 if ( ImplNumericProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
923 return ComboBox::PreNotify( rNEvt
);
926 bool NumericBox::EventNotify( NotifyEvent
& rNEvt
)
928 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
929 MarkToBeReformatted( false );
930 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
932 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
936 return ComboBox::EventNotify( rNEvt
);
939 void NumericBox::DataChanged( const DataChangedEvent
& rDCEvt
)
941 ComboBox::DataChanged( rDCEvt
);
943 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
945 OUString sOldDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
946 OUString sOldThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
947 if ( IsDefaultLocale() )
948 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
949 OUString sNewDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
950 OUString sNewThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
951 ImplUpdateSeparators( sOldDecSep
, sNewDecSep
, sOldThSep
, sNewThSep
, this );
956 void NumericBox::Modify()
958 MarkToBeReformatted( true );
962 void NumericBox::ReformatAll()
966 SetUpdateMode( false );
967 sal_Int32 nEntryCount
= GetEntryCount();
968 for ( sal_Int32 i
=0; i
< nEntryCount
; i
++ )
970 ImplNumericReformat( GetEntry( i
), nValue
, aStr
);
972 InsertEntry( aStr
, i
);
974 NumericFormatter::Reformat();
975 SetUpdateMode( true );
978 void NumericBox::InsertValue( sal_Int64 nValue
, sal_Int32 nPos
)
980 ComboBox::InsertEntry( CreateFieldText( nValue
), nPos
);
983 static bool ImplMetricProcessKeyInput( Edit
* pEdit
, const KeyEvent
& rKEvt
,
984 bool, bool bUseThousandSep
, const LocaleDataWrapper
& rWrapper
)
986 // no meaningfull strict format; therefore allow all characters
987 return ImplNumericProcessKeyInput( pEdit
, rKEvt
, false, bUseThousandSep
, rWrapper
);
990 static OUString
ImplMetricGetUnitText(const OUString
& rStr
)
994 for (sal_Int32 i
= rStr
.getLength()-1; i
>= 0; --i
)
996 sal_Unicode c
= rStr
[i
];
997 if ( (c
== '\'') || (c
== '\"') || (c
== '%' ) || unicode::isAlpha(c
) || unicode::isControl(c
) )
1001 if (!aStr
.isEmpty())
1005 return aStr
.makeStringAndClear();
1008 // #104355# support localized measurements
1010 static const OUString
ImplMetricToString( FieldUnit rUnit
)
1012 FieldUnitStringList
* pList
= ImplGetFieldUnits();
1015 // return unit's default string (ie, the first one )
1016 for( FieldUnitStringList::const_iterator it
= pList
->begin(); it
!= pList
->end(); ++it
)
1018 if ( it
->second
== rUnit
)
1026 static FieldUnit
ImplStringToMetric(const OUString
&rMetricString
)
1028 FieldUnitStringList
* pList
= ImplGetCleanedFieldUnits();
1032 OUString aStr
= rMetricString
.toAsciiLowerCase().replaceAll(" ", "");
1033 for( FieldUnitStringList::const_iterator it
= pList
->begin(); it
!= pList
->end(); ++it
)
1035 if ( it
->first
== aStr
)
1043 static FieldUnit
ImplMetricGetUnit(const OUString
& rStr
)
1045 OUString aStr
= ImplMetricGetUnitText( rStr
);
1046 return ImplStringToMetric( aStr
);
1050 #define M *1000000LL
1053 // twip in km = 254 / 14 400 000 000
1054 // expressions too big for default size 32 bit need LL to avoid overflow
1056 static const sal_Int64 aImplFactor
[FUNIT_LINE
+1][FUNIT_LINE
+1] =
1058 mm/100 mm cm m km twip point pica inch foot mile char line */
1059 { 1, 100, 1 K
, 100 K
, 100 M
, 2540, 2540, 2540, 2540,2540*12,2540*12 X
, 53340, 396240},
1060 { 1, 1, 10, 1 K
, 1 M
, 2540, 2540, 2540, 2540,2540*12,2540*12 X
, 5334, 396240},
1061 { 1, 1, 1, 100, 100 K
, 254, 254, 254, 254, 254*12, 254*12 X
, 5334, 39624},
1062 { 1, 1, 1, 1, 1 K
, 254, 254, 254, 254, 254*12, 254*12 X
, 533400, 39624},
1063 { 1, 1, 1, 1, 1, 254, 254, 254, 254, 254*12, 254*12 X
,533400 K
, 39624},
1064 { 1440,144 K
,144 K
,14400 K
,14400LL M
, 1, 20, 240, 1440,1440*12,1440*12 X
, 210, 3120},
1065 { 72, 7200, 7200, 720 K
, 720 M
, 1, 1, 12, 72, 72*12, 72*12 X
, 210, 156},
1066 { 6, 600, 600, 60 K
, 60 M
, 1, 1, 1, 6, 6*12, 6*12 X
, 210, 10},
1067 { 1, 100, 100, 10 K
, 10 M
, 1, 1, 1, 1, 12, 12 X
, 210, 45},
1068 { 1, 100, 100, 10 K
, 10 M
, 1, 1, 1, 1, 1, 1 X
, 210, 45},
1069 { 1, 100, 100, 10 K
, 10 M
, 1, 1, 1, 1, 1, 1 , 210, 45},
1070 { 144, 1440,14400, 14400, 14400, 1, 20, 240, 1440,1440*12, 1440*12 X
, 1, 156 },
1071 { 720,72000,72000, 7200 K
,7200LL M
, 20, 10, 13, 11, 11*12, 11*12 X
, 105, 1 }
1077 static FieldUnit eDefaultUnit
= FUNIT_NONE
;
1079 FieldUnit
MetricField::GetDefaultUnit() { return eDefaultUnit
; }
1080 void MetricField::SetDefaultUnit( FieldUnit meUnit
) { eDefaultUnit
= meUnit
; }
1082 static FieldUnit
ImplMap2FieldUnit( MapUnit meUnit
, long& nDecDigits
)
1086 case MapUnit::Map100thMM
:
1089 case MapUnit::Map10thMM
:
1092 case MapUnit::MapMM
:
1094 case MapUnit::MapCM
:
1096 case MapUnit::Map1000thInch
:
1099 case MapUnit::Map100thInch
:
1102 case MapUnit::Map10thInch
:
1105 case MapUnit::MapInch
:
1107 case MapUnit::MapPoint
:
1109 case MapUnit::MapTwip
:
1112 OSL_FAIL( "default eInUnit" );
1118 static double nonValueDoubleToValueDouble( double nValue
)
1120 return rtl::math::isFinite( nValue
) ? nValue
: 0.0;
1123 sal_Int64
MetricField::ConvertValue( sal_Int64 nValue
, sal_Int64 mnBaseValue
, sal_uInt16 nDecDigits
,
1124 FieldUnit eInUnit
, FieldUnit eOutUnit
)
1126 double nDouble
= nonValueDoubleToValueDouble( ConvertDoubleValue(
1127 (double)nValue
, mnBaseValue
, nDecDigits
, eInUnit
, eOutUnit
) );
1130 // caution: precision loss in double cast
1131 if ( nDouble
<= (double)SAL_MIN_INT64
)
1132 nLong
= SAL_MIN_INT64
;
1133 else if ( nDouble
>= (double)SAL_MAX_INT64
)
1134 nLong
= SAL_MAX_INT64
;
1136 nLong
= static_cast<sal_Int64
>( nDouble
);
1141 sal_Int64
MetricField::ConvertValue( sal_Int64 nValue
, sal_uInt16 nDigits
,
1142 MapUnit eInUnit
, FieldUnit eOutUnit
)
1144 return static_cast<sal_Int64
>(
1145 nonValueDoubleToValueDouble(
1146 ConvertDoubleValue( nValue
, nDigits
, eInUnit
, eOutUnit
) ) );
1149 double MetricField::ConvertDoubleValue( double nValue
, sal_Int64 mnBaseValue
, sal_uInt16 nDecDigits
,
1150 FieldUnit eInUnit
, FieldUnit eOutUnit
)
1152 if ( eInUnit
!= eOutUnit
)
1154 sal_Int64 nMult
= 1, nDiv
= 1;
1156 if ( eInUnit
== FUNIT_PERCENT
)
1158 if ( (mnBaseValue
<= 0) || (nValue
<= 0) )
1160 nDiv
= 100 * ImplPower10(nDecDigits
);
1162 nMult
= mnBaseValue
;
1164 else if ( eOutUnit
== FUNIT_PERCENT
||
1165 eOutUnit
== FUNIT_CUSTOM
||
1166 eOutUnit
== FUNIT_NONE
||
1167 eOutUnit
== FUNIT_DEGREE
||
1168 eOutUnit
== FUNIT_SECOND
||
1169 eOutUnit
== FUNIT_MILLISECOND
||
1170 eOutUnit
== FUNIT_PIXEL
||
1171 eInUnit
== FUNIT_CUSTOM
||
1172 eInUnit
== FUNIT_NONE
||
1173 eInUnit
== FUNIT_DEGREE
||
1174 eInUnit
== FUNIT_MILLISECOND
||
1175 eInUnit
== FUNIT_PIXEL
)
1179 if ( eOutUnit
== FUNIT_100TH_MM
)
1180 eOutUnit
= FUNIT_NONE
;
1181 if ( eInUnit
== FUNIT_100TH_MM
)
1182 eInUnit
= FUNIT_NONE
;
1184 nDiv
= aImplFactor
[eInUnit
][eOutUnit
];
1185 nMult
= aImplFactor
[eOutUnit
][eInUnit
];
1187 SAL_WARN_IF( nMult
<= 0, "vcl", "illegal *" );
1188 SAL_WARN_IF( nDiv
<= 0, "vcl", "illegal /" );
1191 if ( nMult
!= 1 && nMult
> 0 )
1193 if ( nDiv
!= 1 && nDiv
> 0 )
1195 nValue
+= ( nValue
< 0 ) ? (-nDiv
/2) : (nDiv
/2);
1203 double MetricField::ConvertDoubleValue( double nValue
, sal_uInt16 nDigits
,
1204 MapUnit eInUnit
, FieldUnit eOutUnit
)
1206 if ( eOutUnit
== FUNIT_PERCENT
||
1207 eOutUnit
== FUNIT_CUSTOM
||
1208 eOutUnit
== FUNIT_NONE
||
1209 eInUnit
== MapUnit::MapPixel
||
1210 eInUnit
== MapUnit::MapSysFont
||
1211 eInUnit
== MapUnit::MapAppFont
||
1212 eInUnit
== MapUnit::MapRelative
)
1214 OSL_FAIL( "invalid parameters" );
1218 long nDecDigits
= nDigits
;
1219 FieldUnit eFieldUnit
= ImplMap2FieldUnit( eInUnit
, nDecDigits
);
1221 if ( nDecDigits
< 0 )
1223 while ( nDecDigits
)
1232 nValue
*= ImplPower10(nDecDigits
);
1235 if ( eFieldUnit
!= eOutUnit
)
1237 sal_Int64 nDiv
= aImplFactor
[eFieldUnit
][eOutUnit
];
1238 sal_Int64 nMult
= aImplFactor
[eOutUnit
][eFieldUnit
];
1240 SAL_WARN_IF( nMult
<= 0, "vcl", "illegal *" );
1241 SAL_WARN_IF( nDiv
<= 0, "vcl", "illegal /" );
1243 if ( nMult
!= 1 && nMult
> 0)
1245 if ( nDiv
!= 1 && nDiv
> 0 )
1247 nValue
+= (nValue
< 0) ? (-nDiv
/2) : (nDiv
/2);
1254 double MetricField::ConvertDoubleValue( double nValue
, sal_uInt16 nDigits
,
1255 FieldUnit eInUnit
, MapUnit eOutUnit
)
1257 if ( eInUnit
== FUNIT_PERCENT
||
1258 eInUnit
== FUNIT_CUSTOM
||
1259 eInUnit
== FUNIT_NONE
||
1260 eInUnit
== FUNIT_DEGREE
||
1261 eInUnit
== FUNIT_SECOND
||
1262 eInUnit
== FUNIT_MILLISECOND
||
1263 eInUnit
== FUNIT_PIXEL
||
1264 eOutUnit
== MapUnit::MapPixel
||
1265 eOutUnit
== MapUnit::MapSysFont
||
1266 eOutUnit
== MapUnit::MapAppFont
||
1267 eOutUnit
== MapUnit::MapRelative
)
1269 OSL_FAIL( "invalid parameters" );
1273 long nDecDigits
= nDigits
;
1274 FieldUnit eFieldUnit
= ImplMap2FieldUnit( eOutUnit
, nDecDigits
);
1276 if ( nDecDigits
< 0 )
1278 nValue
*= ImplPower10(-nDecDigits
);
1282 nValue
/= ImplPower10(nDecDigits
);
1285 if ( eFieldUnit
!= eInUnit
)
1287 sal_Int64 nDiv
= aImplFactor
[eInUnit
][eFieldUnit
];
1288 sal_Int64 nMult
= aImplFactor
[eFieldUnit
][eInUnit
];
1290 SAL_WARN_IF( nMult
<= 0, "vcl", "illegal *" );
1291 SAL_WARN_IF( nDiv
<= 0, "vcl", "illegal /" );
1293 if( nMult
!= 1 && nMult
> 0 )
1295 if( nDiv
!= 1 && nDiv
> 0 )
1297 nValue
+= (nValue
< 0) ? (-nDiv
/2) : (nDiv
/2);
1304 static bool ImplMetricGetValue( const OUString
& rStr
, double& rValue
, sal_Int64 nBaseValue
,
1305 sal_uInt16 nDecDigits
, const LocaleDataWrapper
& rLocaleDataWrapper
, FieldUnit eUnit
)
1309 if ( !ImplNumericGetValue( rStr
, nValue
, nDecDigits
, rLocaleDataWrapper
) )
1313 FieldUnit eEntryUnit
= ImplMetricGetUnit( rStr
);
1316 // caution: conversion to double loses precision
1317 rValue
= MetricField::ConvertDoubleValue( (double)nValue
, nBaseValue
, nDecDigits
, eEntryUnit
, eUnit
);
1322 bool MetricFormatter::ImplMetricReformat( const OUString
& rStr
, double& rValue
, OUString
& rOutStr
)
1324 if ( !ImplMetricGetValue( rStr
, rValue
, mnBaseValue
, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit
) )
1328 double nTempVal
= rValue
;
1329 // caution: precision loss in double cast
1330 if ( nTempVal
> GetMax() )
1331 nTempVal
= (double)GetMax();
1332 else if ( nTempVal
< GetMin())
1333 nTempVal
= (double)GetMin();
1335 rOutStr
= CreateFieldText( (sal_Int64
)nTempVal
);
1340 inline void MetricFormatter::ImplInit()
1343 meUnit
= MetricField::GetDefaultUnit();
1344 mnType
= FORMAT_METRIC
;
1347 MetricFormatter::MetricFormatter()
1352 MetricFormatter::~MetricFormatter()
1356 void MetricFormatter::SetUnit( FieldUnit eNewUnit
)
1358 if ( eNewUnit
== FUNIT_100TH_MM
)
1360 SetDecimalDigits( GetDecimalDigits() + 2 );
1368 void MetricFormatter::SetCustomUnitText( const OUString
& rStr
)
1370 maCustomUnitText
= rStr
;
1374 void MetricFormatter::SetValue( sal_Int64 nNewValue
, FieldUnit eInUnit
)
1376 SetUserValue( nNewValue
, eInUnit
);
1377 mnFieldValue
= mnLastValue
;
1380 OUString
MetricFormatter::CreateFieldText( sal_Int64 nValue
) const
1382 //whether percent is separated from its number is locale
1383 //specific, pawn it off to icu to decide
1384 if (meUnit
== FUNIT_PERCENT
)
1386 double dValue
= nValue
;
1387 dValue
/= ImplPower10(GetDecimalDigits());
1388 return unicode::formatPercent(dValue
, Application::GetSettings().GetUILanguageTag());
1391 OUString aStr
= NumericFormatter::CreateFieldText( nValue
);
1393 if( meUnit
== FUNIT_CUSTOM
)
1394 aStr
+= maCustomUnitText
;
1397 if (meUnit
!= FUNIT_NONE
&& meUnit
!= FUNIT_DEGREE
)
1399 assert(meUnit
!= FUNIT_PERCENT
);
1400 aStr
+= ImplMetricToString( meUnit
);
1405 void MetricFormatter::SetUserValue( sal_Int64 nNewValue
, FieldUnit eInUnit
)
1407 // convert to previously configured units
1408 nNewValue
= MetricField::ConvertValue( nNewValue
, mnBaseValue
, GetDecimalDigits(), eInUnit
, meUnit
);
1409 NumericFormatter::SetUserValue( nNewValue
);
1412 sal_Int64
MetricFormatter::GetValue( FieldUnit eOutUnit
) const
1418 // caution: precision loss in double cast
1419 if ( !ImplMetricGetValue( GetField()->GetText(), nTempValue
, mnBaseValue
, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit
) )
1420 nTempValue
= (double)mnLastValue
;
1422 // caution: precision loss in double cast
1423 if ( nTempValue
> mnMax
)
1424 nTempValue
= (double)mnMax
;
1425 else if ( nTempValue
< mnMin
)
1426 nTempValue
= (double)mnMin
;
1428 // convert to requested units
1429 return MetricField::ConvertValue( (sal_Int64
)nTempValue
, mnBaseValue
, GetDecimalDigits(), meUnit
, eOutUnit
);
1432 void MetricFormatter::SetValue( sal_Int64 nValue
)
1434 // Implementation not inline, because it is a virtual Function
1435 SetValue( nValue
, FUNIT_NONE
);
1438 sal_Int64
MetricFormatter::GetValue() const
1440 // Implementation not inline, because it is a virtual Function
1441 return GetValue( FUNIT_NONE
);
1444 void MetricFormatter::SetMin( sal_Int64 nNewMin
, FieldUnit eInUnit
)
1446 // convert to requested units
1447 NumericFormatter::SetMin( MetricField::ConvertValue( nNewMin
, mnBaseValue
, GetDecimalDigits(),
1448 eInUnit
, meUnit
) );
1451 sal_Int64
MetricFormatter::GetMin( FieldUnit eOutUnit
) const
1453 // convert to requested units
1454 return MetricField::ConvertValue( NumericFormatter::GetMin(), mnBaseValue
,
1455 GetDecimalDigits(), meUnit
, eOutUnit
);
1458 void MetricFormatter::SetMax( sal_Int64 nNewMax
, FieldUnit eInUnit
)
1460 // convert to requested units
1461 NumericFormatter::SetMax( MetricField::ConvertValue( nNewMax
, mnBaseValue
, GetDecimalDigits(),
1462 eInUnit
, meUnit
) );
1465 sal_Int64
MetricFormatter::GetMax( FieldUnit eOutUnit
) const
1467 // convert to requested units
1468 return MetricField::ConvertValue( NumericFormatter::GetMax(), mnBaseValue
,
1469 GetDecimalDigits(), meUnit
, eOutUnit
);
1472 void MetricFormatter::SetBaseValue( sal_Int64 nNewBase
, FieldUnit eInUnit
)
1474 mnBaseValue
= MetricField::ConvertValue( nNewBase
, mnBaseValue
, GetDecimalDigits(),
1478 sal_Int64
MetricFormatter::GetBaseValue() const
1480 // convert to requested units
1481 return MetricField::ConvertValue( mnBaseValue
, mnBaseValue
, GetDecimalDigits(),
1482 meUnit
, FUNIT_NONE
);
1485 void MetricFormatter::Reformat()
1490 OUString aText
= GetField()->GetText();
1491 if ( meUnit
== FUNIT_CUSTOM
)
1492 maCurUnitText
= ImplMetricGetUnitText( aText
);
1495 // caution: precision loss in double cast
1496 double nTemp
= (double)mnLastValue
;
1497 bool bOK
= ImplMetricReformat( aText
, nTemp
, aStr
);
1498 mnLastValue
= (sal_Int64
)nTemp
;
1503 if ( !aStr
.isEmpty() )
1505 ImplSetText( aStr
);
1506 if ( meUnit
== FUNIT_CUSTOM
)
1510 SetValue( mnLastValue
);
1511 maCurUnitText
.clear();
1514 sal_Int64
MetricFormatter::GetCorrectedValue( FieldUnit eOutUnit
) const
1516 // convert to requested units
1517 return MetricField::ConvertValue( 0/*nCorrectedValue*/, mnBaseValue
, GetDecimalDigits(),
1521 MetricField::MetricField( vcl::Window
* pParent
, WinBits nWinStyle
) :
1522 SpinField( pParent
, nWinStyle
)
1528 void MetricField::dispose()
1530 MetricFormatter::SetField( nullptr );
1531 SpinField::dispose();
1534 Size
MetricField::CalcMinimumSize() const
1536 return calcMinimumSize(*this, *this);
1539 bool MetricField::set_property(const OString
&rKey
, const OString
&rValue
)
1541 if (rKey
== "digits")
1542 SetDecimalDigits(rValue
.toInt32());
1543 else if (rKey
== "spin-size")
1544 SetSpinSize(rValue
.toInt32());
1546 return SpinField::set_property(rKey
, rValue
);
1550 void MetricField::SetUnit( FieldUnit nNewUnit
)
1552 sal_Int64 nRawMax
= GetMax( nNewUnit
);
1553 sal_Int64 nMax
= Denormalize( nRawMax
);
1554 sal_Int64 nMin
= Denormalize( GetMin( nNewUnit
) );
1555 sal_Int64 nFirst
= Denormalize( GetFirst( nNewUnit
) );
1556 sal_Int64 nLast
= Denormalize( GetLast( nNewUnit
) );
1558 MetricFormatter::SetUnit( nNewUnit
);
1560 SetMax( Normalize( nMax
), nNewUnit
);
1561 SetMin( Normalize( nMin
), nNewUnit
);
1562 SetFirst( Normalize( nFirst
), nNewUnit
);
1563 SetLast( Normalize( nLast
), nNewUnit
);
1566 void MetricField::SetFirst( sal_Int64 nNewFirst
, FieldUnit eInUnit
)
1569 nNewFirst
= MetricField::ConvertValue( nNewFirst
, mnBaseValue
, GetDecimalDigits(),
1571 mnFirst
= nNewFirst
;
1574 sal_Int64
MetricField::GetFirst( FieldUnit eOutUnit
) const
1577 return MetricField::ConvertValue( mnFirst
, mnBaseValue
, GetDecimalDigits(),
1581 void MetricField::SetLast( sal_Int64 nNewLast
, FieldUnit eInUnit
)
1584 nNewLast
= MetricField::ConvertValue( nNewLast
, mnBaseValue
, GetDecimalDigits(),
1589 sal_Int64
MetricField::GetLast( FieldUnit eOutUnit
) const
1592 return MetricField::ConvertValue( mnLast
, mnBaseValue
, GetDecimalDigits(),
1596 bool MetricField::PreNotify( NotifyEvent
& rNEvt
)
1598 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
1600 if ( ImplMetricProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1604 return SpinField::PreNotify( rNEvt
);
1607 bool MetricField::EventNotify( NotifyEvent
& rNEvt
)
1609 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
1610 MarkToBeReformatted( false );
1611 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
1613 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1617 return SpinField::EventNotify( rNEvt
);
1620 void MetricField::DataChanged( const DataChangedEvent
& rDCEvt
)
1622 SpinField::DataChanged( rDCEvt
);
1624 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
1626 OUString sOldDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
1627 OUString sOldThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
1628 if ( IsDefaultLocale() )
1629 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1630 OUString sNewDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
1631 OUString sNewThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
1632 ImplUpdateSeparators( sOldDecSep
, sNewDecSep
, sOldThSep
, sNewThSep
, this );
1637 void MetricField::Modify()
1639 MarkToBeReformatted( true );
1640 SpinField::Modify();
1643 void MetricField::Up()
1649 void MetricField::Down()
1655 void MetricField::First()
1661 void MetricField::Last()
1667 void MetricField::CustomConvert()
1669 maCustomConvertLink
.Call( *this );
1672 MetricBox::MetricBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
1673 ComboBox( pParent
, nWinStyle
)
1679 void MetricBox::dispose()
1681 MetricFormatter::SetField(nullptr);
1682 ComboBox::dispose();
1685 Size
MetricBox::CalcMinimumSize() const
1687 Size
aRet(calcMinimumSize(*this, *this));
1689 if (IsDropDownBox())
1691 Size
aComboSugg(ComboBox::CalcMinimumSize());
1692 aRet
.Width() = std::max(aRet
.Width(), aComboSugg
.Width());
1693 aRet
.Height() = std::max(aRet
.Height(), aComboSugg
.Height());
1699 bool MetricBox::PreNotify( NotifyEvent
& rNEvt
)
1701 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
1703 if ( ImplMetricProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1707 return ComboBox::PreNotify( rNEvt
);
1710 bool MetricBox::EventNotify( NotifyEvent
& rNEvt
)
1712 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
1713 MarkToBeReformatted( false );
1714 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
1716 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1720 return ComboBox::EventNotify( rNEvt
);
1723 void MetricBox::DataChanged( const DataChangedEvent
& rDCEvt
)
1725 ComboBox::DataChanged( rDCEvt
);
1727 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
1729 OUString sOldDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
1730 OUString sOldThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
1731 if ( IsDefaultLocale() )
1732 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1733 OUString sNewDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
1734 OUString sNewThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
1735 ImplUpdateSeparators( sOldDecSep
, sNewDecSep
, sOldThSep
, sNewThSep
, this );
1740 void MetricBox::Modify()
1742 MarkToBeReformatted( true );
1746 void MetricBox::ReformatAll()
1750 SetUpdateMode( false );
1751 sal_Int32 nEntryCount
= GetEntryCount();
1752 for ( sal_Int32 i
=0; i
< nEntryCount
; i
++ )
1754 ImplMetricReformat( GetEntry( i
), nValue
, aStr
);
1756 InsertEntry( aStr
, i
);
1758 MetricFormatter::Reformat();
1759 SetUpdateMode( true );
1762 void MetricBox::CustomConvert()
1764 maCustomConvertLink
.Call( *this );
1767 void MetricBox::InsertValue( sal_Int64 nValue
, FieldUnit eInUnit
, sal_Int32 nPos
)
1769 // convert to previously configured units
1770 nValue
= MetricField::ConvertValue( nValue
, mnBaseValue
, GetDecimalDigits(),
1772 ComboBox::InsertEntry( CreateFieldText( nValue
), nPos
);
1775 sal_Int64
MetricBox::GetValue( sal_Int32 nPos
) const
1778 ImplMetricGetValue( ComboBox::GetEntry( nPos
), nValue
, mnBaseValue
,
1779 GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit
);
1781 // convert to previously configured units
1782 sal_Int64 nRetValue
= MetricField::ConvertValue( (sal_Int64
)nValue
, mnBaseValue
, GetDecimalDigits(),
1783 meUnit
, FUNIT_NONE
);
1788 sal_Int32
MetricBox::GetValuePos( sal_Int64 nValue
, FieldUnit eInUnit
) const
1790 // convert to previously configured units
1791 nValue
= MetricField::ConvertValue( nValue
, mnBaseValue
, GetDecimalDigits(),
1793 return ComboBox::GetEntryPos( CreateFieldText( nValue
) );
1796 sal_Int64
MetricBox::GetValue( FieldUnit eOutUnit
) const
1798 // Implementation not inline, because it is a virtual Function
1799 return MetricFormatter::GetValue( eOutUnit
);
1802 sal_Int64
MetricBox::GetValue() const
1804 // Implementation not inline, because it is a virtual Function
1805 return GetValue( FUNIT_NONE
);
1808 static bool ImplCurrencyProcessKeyInput( Edit
* pEdit
, const KeyEvent
& rKEvt
,
1809 bool, bool bUseThousandSep
, const LocaleDataWrapper
& rWrapper
)
1811 // no strict format set; therefore allow all characters
1812 return ImplNumericProcessKeyInput( pEdit
, rKEvt
, false, bUseThousandSep
, rWrapper
);
1815 inline bool ImplCurrencyGetValue( const OUString
& rStr
, sal_Int64
& rValue
,
1816 sal_uInt16 nDecDigits
, const LocaleDataWrapper
& rWrapper
)
1819 return ImplNumericGetValue( rStr
, rValue
, nDecDigits
, rWrapper
, true );
1822 bool CurrencyFormatter::ImplCurrencyReformat( const OUString
& rStr
, OUString
& rOutStr
)
1825 if ( !ImplNumericGetValue( rStr
, nValue
, GetDecimalDigits(), ImplGetLocaleDataWrapper(), true ) )
1829 sal_Int64 nTempVal
= nValue
;
1830 if ( nTempVal
> GetMax() )
1831 nTempVal
= GetMax();
1832 else if ( nTempVal
< GetMin())
1833 nTempVal
= GetMin();
1835 rOutStr
= CreateFieldText( nTempVal
);
1840 CurrencyFormatter::CurrencyFormatter()
1842 mnType
= FORMAT_CURRENCY
;
1845 CurrencyFormatter::~CurrencyFormatter()
1849 void CurrencyFormatter::SetValue( sal_Int64 nNewValue
)
1851 SetUserValue( nNewValue
);
1852 mnFieldValue
= mnLastValue
;
1853 SetEmptyFieldValueData( false );
1856 OUString
CurrencyFormatter::CreateFieldText( sal_Int64 nValue
) const
1858 return ImplGetLocaleDataWrapper().getCurr( nValue
, GetDecimalDigits(),
1859 ImplGetLocaleDataWrapper().getCurrSymbol(),
1860 IsUseThousandSep() );
1863 sal_Int64
CurrencyFormatter::GetValue() const
1868 sal_Int64 nTempValue
;
1869 if ( ImplCurrencyGetValue( GetField()->GetText(), nTempValue
, GetDecimalDigits(), ImplGetLocaleDataWrapper() ) )
1871 return ClipAgainstMinMax(nTempValue
);
1877 void CurrencyFormatter::Reformat()
1883 bool bOK
= ImplCurrencyReformat( GetField()->GetText(), aStr
);
1887 if ( !aStr
.isEmpty() )
1889 ImplSetText( aStr
);
1890 sal_Int64 nTemp
= mnLastValue
;
1891 ImplCurrencyGetValue( aStr
, nTemp
, GetDecimalDigits(), ImplGetLocaleDataWrapper() );
1892 mnLastValue
= nTemp
;
1895 SetValue( mnLastValue
);
1898 CurrencyField::CurrencyField( vcl::Window
* pParent
, WinBits nWinStyle
) :
1899 SpinField( pParent
, nWinStyle
)
1905 void CurrencyField::dispose()
1907 CurrencyFormatter::SetField( nullptr );
1908 SpinField::dispose();
1911 bool CurrencyField::PreNotify( NotifyEvent
& rNEvt
)
1913 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
1915 if ( ImplCurrencyProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1919 return SpinField::PreNotify( rNEvt
);
1922 bool CurrencyField::EventNotify( NotifyEvent
& rNEvt
)
1924 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
1925 MarkToBeReformatted( false );
1926 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
1928 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1932 return SpinField::EventNotify( rNEvt
);
1935 void CurrencyField::DataChanged( const DataChangedEvent
& rDCEvt
)
1937 SpinField::DataChanged( rDCEvt
);
1939 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
1941 OUString sOldDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
1942 OUString sOldThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
1943 if ( IsDefaultLocale() )
1944 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
1945 OUString sNewDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
1946 OUString sNewThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
1947 ImplUpdateSeparators( sOldDecSep
, sNewDecSep
, sOldThSep
, sNewThSep
, this );
1952 void CurrencyField::Modify()
1954 MarkToBeReformatted( true );
1955 SpinField::Modify();
1958 void CurrencyField::Up()
1964 void CurrencyField::Down()
1970 void CurrencyField::First()
1976 void CurrencyField::Last()
1982 CurrencyBox::CurrencyBox( vcl::Window
* pParent
, WinBits nWinStyle
) :
1983 ComboBox( pParent
, nWinStyle
)
1989 void CurrencyBox::dispose()
1991 CurrencyFormatter::SetField( nullptr );
1992 ComboBox::dispose();
1995 bool CurrencyBox::PreNotify( NotifyEvent
& rNEvt
)
1997 if ( (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
) && !rNEvt
.GetKeyEvent()->GetKeyCode().IsMod2() )
1999 if ( ImplCurrencyProcessKeyInput( GetField(), *rNEvt
.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
2003 return ComboBox::PreNotify( rNEvt
);
2006 bool CurrencyBox::EventNotify( NotifyEvent
& rNEvt
)
2008 if ( rNEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
2009 MarkToBeReformatted( false );
2010 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
2012 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
2016 return ComboBox::EventNotify( rNEvt
);
2019 void CurrencyBox::DataChanged( const DataChangedEvent
& rDCEvt
)
2021 ComboBox::DataChanged( rDCEvt
);
2023 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::LOCALE
) )
2025 OUString sOldDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
2026 OUString sOldThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
2027 if ( IsDefaultLocale() )
2028 ImplGetLocaleDataWrapper().setLanguageTag( GetSettings().GetLanguageTag() );
2029 OUString sNewDecSep
= ImplGetLocaleDataWrapper().getNumDecimalSep();
2030 OUString sNewThSep
= ImplGetLocaleDataWrapper().getNumThousandSep();
2031 ImplUpdateSeparators( sOldDecSep
, sNewDecSep
, sOldThSep
, sNewThSep
, this );
2036 void CurrencyBox::Modify()
2038 MarkToBeReformatted( true );
2042 void CurrencyBox::ReformatAll()
2045 SetUpdateMode( false );
2046 sal_Int32 nEntryCount
= GetEntryCount();
2047 for ( sal_Int32 i
=0; i
< nEntryCount
; i
++ )
2049 ImplCurrencyReformat( GetEntry( i
), aStr
);
2051 InsertEntry( aStr
, i
);
2053 CurrencyFormatter::Reformat();
2054 SetUpdateMode( true );
2057 sal_Int64
CurrencyBox::GetValue() const
2059 // Implementation not inline, because it is a virtual Function
2060 return CurrencyFormatter::GetValue();
2063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */