fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / vcl / source / control / longcurr.cxx
blob6f070afeccc8327bc8a2c24e7b2fe463e5b0c9a1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <comphelper/string.hxx>
21 #include <sot/object.hxx>
22 #include <sot/factory.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/bigint.hxx>
26 #include <tools/rc.h>
28 #include <vcl/event.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/longcurr.hxx>
32 #include <svdata.hxx>
34 #include <unotools/localedatawrapper.hxx>
36 using namespace ::comphelper;
38 #define FORMAT_LONGCURRENCY 4
40 static BigInt ImplPower10( sal_uInt16 n )
42 sal_uInt16 i;
43 BigInt nValue = 1;
45 for ( i=0; i < n; i++ )
46 nValue *= 10;
48 return nValue;
51 static XubString ImplGetCurr( const LocaleDataWrapper& rLocaleDataWrapper, const BigInt &rNumber, sal_uInt16 nDigits, const String& rCurrSymbol, sal_Bool bShowThousandSep )
53 DBG_ASSERT( nDigits < 10, "LongCurrency may only have 9 decimal places" );
55 if ( rNumber.IsZero() || (long)rNumber )
56 return rLocaleDataWrapper.getCurr( (long)rNumber, nDigits, rCurrSymbol, bShowThousandSep );
58 BigInt aTmp( ImplPower10( nDigits ) );
59 BigInt aInteger( rNumber );
60 aInteger.Abs();
61 aInteger /= aTmp;
62 BigInt aFraction( rNumber );
63 aFraction.Abs();
64 aFraction %= aTmp;
65 if ( !aInteger.IsZero() )
67 aFraction += aTmp;
68 aTmp = 1000000000L;
70 if ( rNumber.IsNeg() )
71 aFraction *= -1;
73 XubString aTemplate = rLocaleDataWrapper.getCurr( (long)aFraction, nDigits, rCurrSymbol, bShowThousandSep );
74 while( !aInteger.IsZero() )
76 aFraction = aInteger;
77 aFraction %= aTmp;
78 aInteger /= aTmp;
79 if( !aInteger.IsZero() )
80 aFraction += aTmp;
82 XubString aFractionStr = rLocaleDataWrapper.getNum( (long)aFraction, 0 );
84 xub_StrLen nSPos = aTemplate.Search( '1' );
85 if ( aFractionStr.Len() == 1 )
86 aTemplate.SetChar( nSPos, aFractionStr.GetChar( 0 ) );
87 else
89 aTemplate.Erase( nSPos, 1 );
90 aTemplate.Insert( aFractionStr, nSPos );
94 return aTemplate;
97 static bool ImplNumericProcessKeyInput( Edit*, const KeyEvent& rKEvt,
98 sal_Bool bStrictFormat, sal_Bool bThousandSep,
99 const LocaleDataWrapper& rLocaleDataWrapper )
101 if ( !bStrictFormat )
102 return false;
103 else
105 sal_Unicode cChar = rKEvt.GetCharCode();
106 sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
108 if ( (nGroup == KEYGROUP_FKEYS) || (nGroup == KEYGROUP_CURSOR) ||
109 (nGroup == KEYGROUP_MISC) ||
110 ((cChar >= '0') && (cChar <= '9')) ||
111 (bThousandSep && string::equals(rLocaleDataWrapper.getNumThousandSep(), cChar)) ||
112 (string::equals(rLocaleDataWrapper.getNumDecimalSep(), cChar) ) ||
113 (cChar == '-') )
114 return false;
115 else
116 return true;
120 static bool ImplNumericGetValue( const XubString& rStr, BigInt& rValue,
121 sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper,
122 sal_Bool bCurrency = sal_False )
124 XubString aStr = rStr;
125 XubString aStr1;
126 OUStringBuffer aStr2;
127 sal_uInt16 nDecPos;
128 sal_Bool bNegative = sal_False;
130 // On empty string
131 if ( !rStr.Len() )
132 return false;
134 // Trim leading and trailing spaces
135 aStr = string::strip(aStr, ' ');
137 // Find decimal sign's position
138 nDecPos = aStr.Search( rLocaleDataWrapper.getNumDecimalSep() );
140 if ( nDecPos != STRING_NOTFOUND )
142 aStr1 = aStr.Copy( 0, nDecPos );
143 aStr2.append(aStr.Copy(nDecPos+1));
145 else
146 aStr1 = aStr;
148 // Negative?
149 if ( bCurrency )
151 if ( (aStr.GetChar( 0 ) == '(') && (aStr.GetChar( aStr.Len()-1 ) == ')') )
152 bNegative = sal_True;
153 if ( !bNegative )
155 for (xub_StrLen i=0; i < aStr.Len(); i++ )
157 if ( (aStr.GetChar( i ) >= '0') && (aStr.GetChar( i ) <= '9') )
158 break;
159 else if ( aStr.GetChar( i ) == '-' )
161 bNegative = sal_True;
162 break;
166 if ( !bNegative && bCurrency && aStr.Len() )
168 sal_uInt16 nFormat = rLocaleDataWrapper.getCurrNegativeFormat();
169 if ( (nFormat == 3) || (nFormat == 6) ||
170 (nFormat == 7) || (nFormat == 10) )
172 for (xub_StrLen i = (sal_uInt16)(aStr.Len()-1); i > 0; i++ )
174 if ( (aStr.GetChar( i ) >= '0') && (aStr.GetChar( i ) <= '9') )
175 break;
176 else if ( aStr.GetChar( i ) == '-' )
178 bNegative = sal_True;
179 break;
185 else
187 if ( aStr1.GetChar( 0 ) == '-' )
188 bNegative = sal_True;
191 // delete unwanted characters
192 for (xub_StrLen i=0; i < aStr1.Len(); )
194 if ( (aStr1.GetChar( i ) >= '0') && (aStr1.GetChar( i ) <= '9') )
195 i++;
196 else
197 aStr1.Erase( i, 1 );
199 for (sal_Int32 i=0; i < aStr2.getLength();)
201 if ((aStr2[i] >= '0') && (aStr2[i] <= '9'))
202 ++i;
203 else
204 aStr2.remove(i, 1);
207 if (!aStr1.Len() && !aStr2.getLength())
208 return false;
210 if ( !aStr1.Len() )
211 aStr1.Insert( '0' );
212 if ( bNegative )
213 aStr1.Insert( '-', 0 );
215 // Cut down decimal part and round while doing so
216 bool bRound = false;
217 if (aStr2.getLength() > nDecDigits)
219 if (aStr2[nDecDigits] >= '5')
220 bRound = true;
221 string::truncateToLength(aStr2, nDecDigits);
223 if (aStr2.getLength() < nDecDigits)
224 string::padToLength(aStr2, nDecDigits, '0');
226 aStr = aStr1;
227 aStr += aStr2.makeStringAndClear();
229 // check range
230 BigInt nValue( aStr );
231 if ( bRound )
233 if ( !bNegative )
234 nValue+=1;
235 else
236 nValue-=1;
239 rValue = nValue;
241 return true;
244 static bool ImplLongCurrencyProcessKeyInput( Edit* pEdit, const KeyEvent& rKEvt,
245 sal_Bool, sal_Bool bUseThousandSep, const LocaleDataWrapper& rLocaleDataWrapper )
247 // There's no StrictFormat that makes sense here, thus allow all chars
248 return ImplNumericProcessKeyInput( pEdit, rKEvt, sal_False, bUseThousandSep, rLocaleDataWrapper );
251 inline bool ImplLongCurrencyGetValue( const XubString& rStr, BigInt& rValue,
252 sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper )
254 return ImplNumericGetValue( rStr, rValue, nDecDigits, rLocaleDataWrapper, sal_True );
257 bool ImplLongCurrencyReformat( const XubString& rStr, BigInt nMin, BigInt nMax,
258 sal_uInt16 nDecDigits,
259 const LocaleDataWrapper& rLocaleDataWrapper, String& rOutStr,
260 LongCurrencyFormatter& rFormatter )
262 BigInt nValue;
263 if ( !ImplNumericGetValue( rStr, nValue, nDecDigits, rLocaleDataWrapper, sal_True ) )
264 return true;
265 else
267 BigInt nTempVal = nValue;
268 if ( nTempVal > nMax )
269 nTempVal = nMax;
270 else if ( nTempVal < nMin )
271 nTempVal = nMin;
273 if ( rFormatter.GetErrorHdl().IsSet() && (nValue != nTempVal) )
275 rFormatter.mnCorrectedValue = nTempVal;
276 if ( !rFormatter.GetErrorHdl().Call( &rFormatter ) )
278 rFormatter.mnCorrectedValue = 0;
279 return false;
281 else
283 rFormatter.mnCorrectedValue = 0;
287 rOutStr = ImplGetCurr( rLocaleDataWrapper, nTempVal, nDecDigits, rFormatter.GetCurrencySymbol(), rFormatter.IsUseThousandSep() );
288 return true;
292 void LongCurrencyFormatter::ImpInit()
294 mnFieldValue = 0;
295 mnLastValue = 0;
296 mnMin = 0;
297 mnMax = 0x7FFFFFFF;
298 mnMax *= 0x7FFFFFFF;
299 mnCorrectedValue = 0;
300 mnDecimalDigits = 0;
301 mnType = FORMAT_LONGCURRENCY;
302 mbThousandSep = sal_True;
303 SetDecimalDigits( 0 );
306 LongCurrencyFormatter::LongCurrencyFormatter()
308 ImpInit();
311 LongCurrencyFormatter::~LongCurrencyFormatter()
315 void LongCurrencyFormatter::SetCurrencySymbol( const String& rStr )
317 maCurrencySymbol= rStr;
318 ReformatAll();
321 String LongCurrencyFormatter::GetCurrencySymbol() const
323 return !maCurrencySymbol.isEmpty() ? maCurrencySymbol : GetLocaleDataWrapper().getCurrSymbol();
326 void LongCurrencyFormatter::SetValue( BigInt nNewValue )
328 SetUserValue( nNewValue );
329 mnFieldValue = mnLastValue;
330 SetEmptyFieldValueData( sal_False );
333 void LongCurrencyFormatter::SetUserValue( BigInt nNewValue )
335 if ( nNewValue > mnMax )
336 nNewValue = mnMax;
337 else if ( nNewValue < mnMin )
338 nNewValue = mnMin;
339 mnLastValue = nNewValue;
341 if ( !GetField() )
342 return;
344 XubString aStr = ImplGetCurr( GetLocaleDataWrapper(), nNewValue, GetDecimalDigits(), GetCurrencySymbol(), IsUseThousandSep() );
345 if ( GetField()->HasFocus() )
347 Selection aSelection = GetField()->GetSelection();
348 GetField()->SetText( aStr );
349 GetField()->SetSelection( aSelection );
351 else
352 GetField()->SetText( aStr );
353 MarkToBeReformatted( sal_False );
356 BigInt LongCurrencyFormatter::GetValue() const
358 if ( !GetField() )
359 return 0;
361 BigInt nTempValue;
362 if ( ImplLongCurrencyGetValue( GetField()->GetText(), nTempValue, GetDecimalDigits(), GetLocaleDataWrapper() ) )
364 if ( nTempValue > mnMax )
365 nTempValue = mnMax;
366 else if ( nTempValue < mnMin )
367 nTempValue = mnMin;
368 return nTempValue;
370 else
371 return mnLastValue;
374 void LongCurrencyFormatter::Reformat()
376 if ( !GetField() )
377 return;
379 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
380 return;
382 XubString aStr;
383 bool bOK = ImplLongCurrencyReformat( GetField()->GetText(), mnMin, mnMax,
384 GetDecimalDigits(), GetLocaleDataWrapper(), aStr, *this );
385 if ( !bOK )
386 return;
388 if ( aStr.Len() )
390 GetField()->SetText( aStr );
391 MarkToBeReformatted( sal_False );
392 ImplLongCurrencyGetValue( aStr, mnLastValue, GetDecimalDigits(), GetLocaleDataWrapper() );
394 else
395 SetValue( mnLastValue );
398 void LongCurrencyFormatter::ReformatAll()
400 Reformat();
403 void LongCurrencyFormatter::SetMin( BigInt nNewMin )
405 mnMin = nNewMin;
406 ReformatAll();
409 void LongCurrencyFormatter::SetMax( BigInt nNewMax )
411 mnMax = nNewMax;
412 ReformatAll();
415 void LongCurrencyFormatter::SetUseThousandSep( sal_Bool b )
417 mbThousandSep = b;
418 ReformatAll();
421 void LongCurrencyFormatter::SetDecimalDigits( sal_uInt16 nDigits )
423 if ( nDigits > 9 )
424 nDigits = 9;
426 mnDecimalDigits = nDigits;
427 ReformatAll();
430 sal_uInt16 LongCurrencyFormatter::GetDecimalDigits() const
432 return mnDecimalDigits;
435 void ImplNewLongCurrencyFieldValue( LongCurrencyField* pField, BigInt nNewValue )
437 Selection aSelect = pField->GetSelection();
438 aSelect.Justify();
439 XubString aText = pField->GetText();
440 bool bLastSelected = ((xub_StrLen)aSelect.Max() == aText.Len());
442 BigInt nOldLastValue = pField->mnLastValue;
443 pField->SetUserValue( nNewValue );
444 pField->mnLastValue = nOldLastValue;
446 if ( bLastSelected )
448 if ( !aSelect.Len() )
449 aSelect.Min() = SELECTION_MAX;
450 aSelect.Max() = SELECTION_MAX;
452 pField->SetSelection( aSelect );
453 pField->SetModifyFlag();
454 pField->Modify();
457 LongCurrencyField::LongCurrencyField( Window* pParent, WinBits nWinStyle ) :
458 SpinField( pParent, nWinStyle )
460 SetField( this );
461 mnSpinSize = 1;
462 mnFirst = mnMin;
463 mnLast = mnMax;
465 Reformat();
469 LongCurrencyField::~LongCurrencyField()
474 long LongCurrencyField::PreNotify( NotifyEvent& rNEvt )
476 if( rNEvt.GetType() == EVENT_KEYINPUT )
478 if ( ImplLongCurrencyProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), GetLocaleDataWrapper() ) )
479 return 1;
481 return SpinField::PreNotify( rNEvt );
485 long LongCurrencyField::Notify( NotifyEvent& rNEvt )
487 if( rNEvt.GetType() == EVENT_GETFOCUS )
489 MarkToBeReformatted( sal_False );
491 else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
493 if ( MustBeReformatted() )
495 Reformat();
496 SpinField::Modify();
499 return SpinField::Notify( rNEvt );
503 void LongCurrencyField::Modify()
505 MarkToBeReformatted( sal_True );
506 SpinField::Modify();
510 void LongCurrencyField::Up()
512 BigInt nValue = GetValue();
513 nValue += mnSpinSize;
514 if ( nValue > mnMax )
515 nValue = mnMax;
517 ImplNewLongCurrencyFieldValue( this, nValue );
518 SpinField::Up();
521 void LongCurrencyField::Down()
523 BigInt nValue = GetValue();
524 nValue -= mnSpinSize;
525 if ( nValue < mnMin )
526 nValue = mnMin;
528 ImplNewLongCurrencyFieldValue( this, nValue );
529 SpinField::Down();
533 void LongCurrencyField::First()
535 ImplNewLongCurrencyFieldValue( this, mnFirst );
536 SpinField::First();
540 void LongCurrencyField::Last()
542 ImplNewLongCurrencyFieldValue( this, mnLast );
543 SpinField::Last();
546 LongCurrencyBox::LongCurrencyBox( Window* pParent, WinBits nWinStyle ) :
547 ComboBox( pParent, nWinStyle )
549 SetField( this );
550 Reformat();
553 LongCurrencyBox::~LongCurrencyBox()
557 long LongCurrencyBox::PreNotify( NotifyEvent& rNEvt )
559 if( rNEvt.GetType() == EVENT_KEYINPUT )
561 if ( ImplLongCurrencyProcessKeyInput( GetField(), *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), GetLocaleDataWrapper() ) )
562 return 1;
564 return ComboBox::PreNotify( rNEvt );
568 long LongCurrencyBox::Notify( NotifyEvent& rNEvt )
570 if( rNEvt.GetType() == EVENT_GETFOCUS )
572 MarkToBeReformatted( sal_False );
574 else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
576 if ( MustBeReformatted() )
578 Reformat();
579 ComboBox::Modify();
582 return ComboBox::Notify( rNEvt );
585 void LongCurrencyBox::Modify()
587 MarkToBeReformatted( sal_True );
588 ComboBox::Modify();
591 void LongCurrencyBox::ReformatAll()
593 XubString aStr;
594 SetUpdateMode( sal_False );
595 sal_uInt16 nEntryCount = GetEntryCount();
596 for ( sal_uInt16 i=0; i < nEntryCount; i++ )
598 ImplLongCurrencyReformat( GetEntry( i ), mnMin, mnMax,
599 GetDecimalDigits(), GetLocaleDataWrapper(),
600 aStr, *this );
601 RemoveEntry( i );
602 InsertEntry( aStr, i );
604 LongCurrencyFormatter::Reformat();
605 SetUpdateMode( sal_True );
608 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */