sdext: adapt xpdfwrapper to poppler 24.12
[LibreOffice.git] / vcl / source / control / longcurr.cxx
blob96afc509dfa21e58d21218d0aa1fd6175c936bae
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 <sal/config.h>
22 #include <string_view>
24 #include <comphelper/string.hxx>
25 #include <tools/bigint.hxx>
26 #include <sal/log.hxx>
28 #include <vcl/event.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/toolkit/longcurr.hxx>
31 #include <vcl/weldutils.hxx>
33 #include <unotools/localedatawrapper.hxx>
35 using namespace ::comphelper;
37 namespace
40 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 OUString ImplGetCurr( const LocaleDataWrapper& rLocaleDataWrapper, const BigInt &rNumber, sal_uInt16 nDigits, std::u16string_view rCurrSymbol, bool bShowThousandSep )
53 SAL_WARN_IF( nDigits >= 10, "vcl", "LongCurrency may only have 9 decimal places" );
55 if ( rNumber.IsZero() || static_cast<tools::Long>(rNumber) )
56 return rLocaleDataWrapper.getCurr( static_cast<tools::Long>(rNumber), nDigits, rCurrSymbol, bShowThousandSep );
58 BigInt aTmp( ImplPower10( nDigits ) );
59 BigInt aInteger;
60 BigInt aFraction;
61 rNumber.Abs().DivMod(aTmp, &aInteger, &aFraction);
62 if ( !aInteger.IsZero() )
64 aFraction += aTmp;
65 aTmp = 1000000000;
67 if ( rNumber.IsNeg() )
68 aFraction *= -1;
70 OUStringBuffer aTemplate(rLocaleDataWrapper.getCurr( static_cast<tools::Long>(aFraction), nDigits, rCurrSymbol, bShowThousandSep ));
71 while( !aInteger.IsZero() )
73 aInteger.DivMod(aTmp, &aInteger, &aFraction);
74 if( !aInteger.IsZero() )
75 aFraction += aTmp;
77 OUString aFractionStr = rLocaleDataWrapper.getNum( static_cast<tools::Long>(aFraction), 0 );
79 sal_Int32 nSPos = aTemplate.indexOf( '1' );
80 if (nSPos == -1)
81 break;
82 if ( aFractionStr.getLength() == 1 )
83 aTemplate[ nSPos ] = aFractionStr[0];
84 else
86 aTemplate.remove( nSPos, 1 );
87 aTemplate.insert( nSPos, aFractionStr );
91 return aTemplate.makeStringAndClear();
94 bool ImplCurrencyGetValue( const OUString& rStr, BigInt& rValue,
95 sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper )
97 OUString aStr = rStr;
98 OUStringBuffer aStr1;
99 OUStringBuffer aStr2;
100 sal_Int32 nDecPos;
101 bool bNegative = false;
103 // On empty string
104 if ( rStr.isEmpty() )
105 return false;
107 // Trim leading and trailing spaces
108 aStr = string::strip(aStr, ' ');
110 // Find decimal sign's position
111 nDecPos = aStr.indexOf( rLocaleDataWrapper.getNumDecimalSep() );
112 if (nDecPos < 0 && !rLocaleDataWrapper.getNumDecimalSepAlt().isEmpty())
113 nDecPos = aStr.indexOf( rLocaleDataWrapper.getNumDecimalSepAlt() );
115 if ( nDecPos != -1 )
117 aStr1 = aStr.subView( 0, nDecPos );
118 aStr2.append(aStr.subView(nDecPos+1));
120 else
121 aStr1 = aStr;
123 // Negative?
124 if ( (aStr[ 0 ] == '(') && (aStr[ aStr.getLength()-1 ] == ')') )
125 bNegative = true;
126 if ( !bNegative )
128 for (sal_Int32 i=0; i < aStr.getLength(); i++ )
130 if ( (aStr[ i ] >= '0') && (aStr[ i ] <= '9') )
131 break;
132 else if ( aStr[ i ] == '-' )
134 bNegative = true;
135 break;
139 if ( !bNegative && !aStr.isEmpty() )
141 sal_uInt16 nFormat = rLocaleDataWrapper.getCurrNegativeFormat();
142 if ( (nFormat == 3) || (nFormat == 6) ||
143 (nFormat == 7) || (nFormat == 10) )
145 for (sal_Int32 i = aStr.getLength()-1; i > 0; i++ )
147 if ( (aStr[ i ] >= '0') && (aStr[ i ] <= '9') )
148 break;
149 else if ( aStr[ i ] == '-' )
151 bNegative = true;
152 break;
158 // delete unwanted characters
159 for (sal_Int32 i=0; i < aStr1.getLength(); )
161 if ( (aStr1[ i ] >= '0') && (aStr1[ i ] <= '9') )
162 i++;
163 else
164 aStr1.remove( i, 1 );
166 for (sal_Int32 i=0; i < aStr2.getLength(); )
168 if ((aStr2[i] >= '0') && (aStr2[i] <= '9'))
169 ++i;
170 else
171 aStr2.remove(i, 1);
174 if ( aStr1.isEmpty() && aStr2.isEmpty())
175 return false;
177 if ( aStr1.isEmpty() )
178 aStr1 = "0";
179 if ( bNegative )
180 aStr1.insert( 0, '-');
182 // Cut down decimal part and round while doing so
183 bool bRound = false;
184 if (aStr2.getLength() > nDecDigits)
186 if (aStr2[nDecDigits] >= '5')
187 bRound = true;
188 string::truncateToLength(aStr2, nDecDigits);
190 string::padToLength(aStr2, nDecDigits, '0');
192 aStr1.append(aStr2);
193 aStr = aStr1.makeStringAndClear();
195 // check range
196 BigInt nValue( aStr );
197 if ( bRound )
199 if ( !bNegative )
200 nValue+=1;
201 else
202 nValue-=1;
205 rValue = nValue;
207 return true;
210 } // namespace
212 static bool ImplLongCurrencyGetValue( const OUString& rStr, BigInt& rValue,
213 sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper )
215 return ImplCurrencyGetValue( rStr, rValue, nDecDigits, rLocaleDataWrapper );
218 namespace weld
220 IMPL_LINK_NOARG(LongCurrencyFormatter, FormatOutputHdl, LinkParamNone*, bool)
222 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
223 const OUString& rCurrencySymbol = !m_aCurrencySymbol.isEmpty() ? m_aCurrencySymbol : rLocaleDataWrapper.getCurrSymbol();
224 double fValue = GetValue();
225 sal_uInt16 nDecimalDigits = GetDecimalDigits();
226 if (nDecimalDigits)
228 // tdf#158669 round to decimal digits
229 fValue = std::round(fValue * weld::SpinButton::Power10(nDecimalDigits));
231 OUString aText = ImplGetCurr(rLocaleDataWrapper, fValue, GetDecimalDigits(), rCurrencySymbol, m_bThousandSep);
232 ImplSetTextImpl(aText, nullptr);
233 return true;
236 IMPL_LINK(LongCurrencyFormatter, ParseInputHdl, sal_Int64*, result, TriState)
238 const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
240 BigInt value;
241 bool bRet = ImplLongCurrencyGetValue(GetEntryText(), value, GetDecimalDigits(), rLocaleDataWrapper);
243 if (bRet)
244 *result = double(value);
246 return bRet ? TRISTATE_TRUE : TRISTATE_FALSE;
250 bool ImplLongCurrencyReformat( const OUString& rStr, BigInt const & nMin, BigInt const & nMax,
251 sal_uInt16 nDecDigits,
252 const LocaleDataWrapper& rLocaleDataWrapper, OUString& rOutStr,
253 LongCurrencyFormatter const & rFormatter )
255 BigInt nValue;
256 if ( !ImplCurrencyGetValue( rStr, nValue, nDecDigits, rLocaleDataWrapper ) )
257 return true;
258 else
260 BigInt nTempVal = nValue;
261 if ( nTempVal > nMax )
262 nTempVal = nMax;
263 else if ( nTempVal < nMin )
264 nTempVal = nMin;
266 rOutStr = ImplGetCurr( rLocaleDataWrapper, nTempVal, nDecDigits, rFormatter.GetCurrencySymbol(), /*IsUseThousandSep*/true );
267 return true;
271 void LongCurrencyFormatter::ImpInit()
273 mnLastValue = 0;
274 mnMin = 0;
275 mnMax = 0x7FFFFFFF;
276 mnMax *= 0x7FFFFFFF;
277 mnDecimalDigits = 0;
278 SetDecimalDigits( 0 );
281 LongCurrencyFormatter::LongCurrencyFormatter(Edit* pEdit)
282 : FormatterBase(pEdit)
284 ImpInit();
287 LongCurrencyFormatter::~LongCurrencyFormatter()
291 OUString const & LongCurrencyFormatter::GetCurrencySymbol() const
293 return GetLocaleDataWrapper().getCurrSymbol();
296 void LongCurrencyFormatter::SetValue(const BigInt& rNewValue)
298 SetUserValue(rNewValue);
299 SetEmptyFieldValueData( false );
302 void LongCurrencyFormatter::SetUserValue( BigInt nNewValue )
304 if ( nNewValue > mnMax )
305 nNewValue = mnMax;
306 else if ( nNewValue < mnMin )
307 nNewValue = mnMin;
308 mnLastValue = nNewValue;
310 if ( !GetField() )
311 return;
313 OUString aStr = ImplGetCurr( GetLocaleDataWrapper(), nNewValue, GetDecimalDigits(), GetCurrencySymbol(), /*UseThousandSep*/true );
314 if ( GetField()->HasFocus() )
316 Selection aSelection = GetField()->GetSelection();
317 GetField()->SetText( aStr );
318 GetField()->SetSelection( aSelection );
320 else
321 GetField()->SetText( aStr );
322 MarkToBeReformatted( false );
325 BigInt LongCurrencyFormatter::GetValue() const
327 if ( !GetField() )
328 return 0;
330 BigInt nTempValue;
331 if ( ImplLongCurrencyGetValue( GetField()->GetText(), nTempValue, GetDecimalDigits(), GetLocaleDataWrapper() ) )
333 if ( nTempValue > mnMax )
334 nTempValue = mnMax;
335 else if ( nTempValue < mnMin )
336 nTempValue = mnMin;
337 return nTempValue;
339 else
340 return mnLastValue;
343 void LongCurrencyFormatter::Reformat()
345 if ( !GetField() )
346 return;
348 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
349 return;
351 OUString aStr;
352 bool bOK = ImplLongCurrencyReformat( GetField()->GetText(), mnMin, mnMax,
353 GetDecimalDigits(), GetLocaleDataWrapper(), aStr, *this );
354 if ( !bOK )
355 return;
357 if ( !aStr.isEmpty() )
359 GetField()->SetText( aStr );
360 MarkToBeReformatted( false );
361 ImplLongCurrencyGetValue( aStr, mnLastValue, GetDecimalDigits(), GetLocaleDataWrapper() );
363 else
364 SetValue( mnLastValue );
367 void LongCurrencyFormatter::ReformatAll()
369 Reformat();
372 void LongCurrencyFormatter::SetDecimalDigits( sal_uInt16 nDigits )
374 if ( nDigits > 9 )
375 nDigits = 9;
377 mnDecimalDigits = nDigits;
378 ReformatAll();
383 LongCurrencyBox::LongCurrencyBox(vcl::Window* pParent, WinBits nWinStyle)
384 : ComboBox(pParent, nWinStyle)
385 , LongCurrencyFormatter(this)
387 Reformat();
390 bool LongCurrencyBox::EventNotify( NotifyEvent& rNEvt )
392 if( rNEvt.GetType() == NotifyEventType::GETFOCUS )
394 MarkToBeReformatted( false );
396 else if( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
398 if ( MustBeReformatted() )
400 Reformat();
401 ComboBox::Modify();
404 return ComboBox::EventNotify( rNEvt );
407 void LongCurrencyBox::Modify()
409 MarkToBeReformatted( true );
410 ComboBox::Modify();
413 void LongCurrencyBox::ReformatAll()
415 OUString aStr;
416 SetUpdateMode( false );
417 const sal_Int32 nEntryCount = GetEntryCount();
418 for ( sal_Int32 i=0; i < nEntryCount; ++i )
420 ImplLongCurrencyReformat( GetEntry( i ), mnMin, mnMax,
421 GetDecimalDigits(), GetLocaleDataWrapper(),
422 aStr, *this );
423 RemoveEntryAt(i);
424 InsertEntry( aStr, i );
426 LongCurrencyFormatter::Reformat();
427 SetUpdateMode( true );
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */