LibreOffice Module vcl (master) 1
field.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <cmath>
23#include <string_view>
24
25#include <sal/log.hxx>
26#include <o3tl/string_view.hxx>
27#include <osl/diagnose.h>
28
29#include <comphelper/string.hxx>
31
32#include <vcl/builder.hxx>
33#include <vcl/fieldvalues.hxx>
34#include <vcl/toolkit/field.hxx>
35#include <vcl/event.hxx>
36#include <vcl/svapp.hxx>
37#include <vcl/settings.hxx>
40
41#include <svdata.hxx>
42
43#include <i18nutil/unicode.hxx>
44
45#include <rtl/math.hxx>
46
48#include <boost/property_tree/ptree.hpp>
49#include <tools/json_writer.hxx>
50
51using namespace ::com::sun::star;
52using namespace ::comphelper;
53
54namespace
55{
56
57std::string FieldUnitToString(FieldUnit unit)
58{
59 switch(unit)
60 {
61 case FieldUnit::NONE:
62 return "";
63
64 case FieldUnit::MM:
65 return "mm";
66
67 case FieldUnit::CM:
68 return "cm";
69
70 case FieldUnit::M:
71 return "m";
72
73 case FieldUnit::KM:
74 return "km";
75
76 case FieldUnit::TWIP:
77 return "twip";
78
79 case FieldUnit::POINT:
80 return "point";
81
82 case FieldUnit::PICA:
83 return "pica";
84
85 case FieldUnit::INCH:
86 return "inch";
87
88 case FieldUnit::FOOT:
89 return "foot";
90
91 case FieldUnit::MILE:
92 return "mile";
93
94 case FieldUnit::CHAR:
95 return "char";
96
97 case FieldUnit::LINE:
98 return "line";
99
100 case FieldUnit::CUSTOM:
101 return "custom";
102
103 case FieldUnit::PERCENT:
104 return "percent";
105
106 case FieldUnit::MM_100TH:
107 return "mm100th";
108
109 case FieldUnit::PIXEL:
110 return "pixel";
111
112 case FieldUnit::DEGREE:
113 return "degree";
114
115 case FieldUnit::SECOND:
116 return "second";
117
118 case FieldUnit::MILLISECOND:
119 return "millisecond";
120 }
121
122 return "";
123}
124
125sal_Int64 ImplPower10( sal_uInt16 n )
126{
127 sal_uInt16 i;
128 sal_Int64 nValue = 1;
129
130 for ( i=0; i < n; i++ )
131 nValue *= 10;
132
133 return nValue;
134}
135
136bool ImplNumericProcessKeyInput( const KeyEvent& rKEvt,
137 bool bStrictFormat, bool bThousandSep,
138 const LocaleDataWrapper& rLocaleDataWrapper )
139{
140 if ( !bStrictFormat )
141 return false;
142 else
143 {
144 sal_Unicode cChar = rKEvt.GetCharCode();
145 sal_uInt16 nGroup = rKEvt.GetKeyCode().GetGroup();
146
147 return !((nGroup == KEYGROUP_FKEYS) ||
148 (nGroup == KEYGROUP_CURSOR) ||
149 (nGroup == KEYGROUP_MISC) ||
150 ((cChar >= '0') && (cChar <= '9')) ||
151 rLocaleDataWrapper.getNumDecimalSep() == OUStringChar(cChar) ||
152 (bThousandSep && rLocaleDataWrapper.getNumThousandSep() == OUStringChar(cChar)) ||
153 rLocaleDataWrapper.getNumDecimalSepAlt() == OUStringChar(cChar) ||
154 (cChar == '-'));
155 }
156}
157
158bool ImplNumericGetValue( const OUString& rStr, sal_Int64& rValue,
159 sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper,
160 bool bCurrency = false )
161{
162 OUString aStr = rStr;
163 OUStringBuffer aStr1, aStr2, aStrNum, aStrDenom;
164 bool bNegative = false;
165 bool bFrac = false;
166 sal_Int32 nDecPos, nFracDivPos;
167 sal_Int64 nValue;
168
169 // react on empty string
170 if ( rStr.isEmpty() )
171 return false;
172
173 // remove leading and trailing spaces
174 aStr = aStr.trim();
175
176
177 // find position of decimal point
178 nDecPos = aStr.indexOf( rLocaleDataWrapper.getNumDecimalSep() );
179 if (nDecPos < 0 && !rLocaleDataWrapper.getNumDecimalSepAlt().isEmpty())
180 nDecPos = aStr.indexOf( rLocaleDataWrapper.getNumDecimalSepAlt() );
181 // find position of fraction
182 nFracDivPos = aStr.indexOf( '/' );
183
184 // parse fractional strings
185 if (nFracDivPos > 0)
186 {
187 bFrac = true;
188 sal_Int32 nFracNumPos = aStr.lastIndexOf(' ', nFracDivPos);
190 // If in "a b/c" format.
191 if(nFracNumPos != -1 )
192 {
193 aStr1.append(aStr.subView(0, nFracNumPos));
194 aStrNum.append(aStr.subView(nFracNumPos+1, nFracDivPos-nFracNumPos-1));
195 aStrDenom.append(aStr.subView(nFracDivPos+1));
196 }
197 // "a/b" format, or not a fraction at all
198 else
199 {
200 aStrNum.append(aStr.subView(0, nFracDivPos));
201 aStrDenom.append(aStr.subView(nFracDivPos+1));
202 }
203
204 }
205 // parse decimal strings
206 else if ( nDecPos >= 0)
207 {
208 aStr1.append(aStr.subView(0, nDecPos));
209 aStr2.append(aStr.subView(nDecPos+1));
210 }
211 else
212 aStr1 = aStr;
213
214 // negative?
215 if ( bCurrency )
216 {
217 if ( aStr.startsWith("(") && aStr.endsWith(")") )
218 bNegative = true;
219 if ( !bNegative )
220 {
221 for (sal_Int32 i=0; i < aStr.getLength(); i++ )
222 {
223 if ( (aStr[i] >= '0') && (aStr[i] <= '9') )
224 break;
225 else if ( aStr[i] == '-' )
226 {
227 bNegative = true;
228 break;
229 }
230 }
231 }
232 if (!bNegative && !aStr.isEmpty())
233 {
234 sal_uInt16 nFormat = rLocaleDataWrapper.getCurrNegativeFormat();
235 if ( (nFormat == 3) || (nFormat == 6) || // $1- || 1-$
236 (nFormat == 7) || (nFormat == 10) ) // 1$- || 1 $-
237 {
238 for (sal_Int32 i = aStr.getLength()-1; i > 0; --i )
239 {
240 if ( (aStr[i] >= '0') && (aStr[i] <= '9') )
241 break;
242 else if ( aStr[i] == '-' )
243 {
244 bNegative = true;
245 break;
246 }
247 }
248 }
249 }
250 }
251 else
252 {
253 if ( !aStr1.isEmpty() && aStr1[0] == '-')
254 bNegative = true;
255 if ( !aStrNum.isEmpty() && aStrNum[0] == '-') // For non-mixed fractions
256 bNegative = true;
257 }
258
259 // remove all unwanted characters
260 // For whole number
261 for (sal_Int32 i=0; i < aStr1.getLength(); )
262 {
263 if ( (aStr1[i] >= '0') && (aStr1[i] <= '9') )
264 i++;
265 else
266 aStr1.remove( i, 1 );
267 }
268 // For decimal
269 if (!bFrac) {
270 for (sal_Int32 i=0; i < aStr2.getLength(); )
271 {
272 if ((aStr2[i] >= '0') && (aStr2[i] <= '9'))
273 ++i;
274 else
275 aStr2.remove(i, 1);
276 }
277 }
278 else {
279 // for numerator
280 for (sal_Int32 i=0; i < aStrNum.getLength(); )
281 {
282 if ((aStrNum[i] >= '0') && (aStrNum[i] <= '9'))
283 ++i;
284 else
285 aStrNum.remove(i, 1);
286 }
287 // for denominator
288 for (sal_Int32 i=0; i < aStrDenom.getLength(); )
289 {
290 if ((aStrDenom[i] >= '0') && (aStrDenom[i] <= '9'))
291 ++i;
292 else
293 aStrDenom.remove(i, 1);
294 }
295 }
296
297
298 if ( !bFrac && aStr1.isEmpty() && aStr2.isEmpty() )
299 return false;
300 else if ( bFrac && aStr1.isEmpty() && (aStrNum.isEmpty() || aStrDenom.isEmpty()) )
301 return false;
302
303 if ( aStr1.isEmpty() )
304 aStr1 = "0";
305 if ( bNegative )
306 aStr1.insert(0, "-");
307
308 // Convert fractional strings
309 if (bFrac) {
310 // Convert to fraction
311 sal_Int64 nWholeNum = o3tl::toInt64(aStr1);
312 aStr1.setLength(0);
313 sal_Int64 nNum = o3tl::toInt64(aStrNum);
314 sal_Int64 nDenom = o3tl::toInt64(aStrDenom);
315 if (nDenom == 0) return false; // Division by zero
316 double nFrac2Dec = nWholeNum + static_cast<double>(nNum)/nDenom; // Convert to double for floating point precision
317 OUStringBuffer aStrFrac(OUString::number(nFrac2Dec));
318 // Reconvert division result to string and parse
319 nDecPos = aStrFrac.indexOf('.');
320 if ( nDecPos >= 0)
321 {
322 aStr1.append(aStrFrac.getStr(), nDecPos);
323 aStr2.append(aStrFrac.getStr()+nDecPos+1);
324 }
325 else
326 aStr1 = aStrFrac;
327 }
328
329 // prune and round fraction
330 bool bRound = false;
331 if (aStr2.getLength() > nDecDigits)
332 {
333 if (aStr2[nDecDigits] >= '5')
334 bRound = true;
335 string::truncateToLength(aStr2, nDecDigits);
336 }
337 if (aStr2.getLength() < nDecDigits)
338 string::padToLength(aStr2, nDecDigits, '0');
339
340 aStr = aStr1 + aStr2;
341
342 // check range
343 nValue = aStr.toInt64();
344 if( nValue == 0 )
345 {
346 // check if string is equivalent to zero
347 sal_Int32 nIndex = bNegative ? 1 : 0;
348 while (nIndex < aStr.getLength() && aStr[nIndex] == '0')
349 ++nIndex;
350 if( nIndex < aStr.getLength() )
351 {
352 rValue = bNegative ? SAL_MIN_INT64 : SAL_MAX_INT64;
353 return true;
354 }
355 }
356 if (bRound)
357 {
358 if ( !bNegative )
359 nValue++;
360 else
361 nValue--;
362 }
363
364 rValue = nValue;
365
366 return true;
367}
368
369void ImplUpdateSeparatorString( OUString& io_rText,
370 std::u16string_view rOldDecSep, std::u16string_view rNewDecSep,
371 std::u16string_view rOldThSep, std::u16string_view rNewThSep )
372{
373 OUStringBuffer aBuf( io_rText.getLength() );
374 sal_Int32 nIndexDec = 0, nIndexTh = 0, nIndex = 0;
375
376 const sal_Unicode* pBuffer = io_rText.getStr();
377 while( nIndex != -1 )
378 {
379 nIndexDec = io_rText.indexOf( rOldDecSep, nIndex );
380 nIndexTh = io_rText.indexOf( rOldThSep, nIndex );
381 if( (nIndexTh != -1 && nIndexDec != -1 && nIndexTh < nIndexDec )
382 || (nIndexTh != -1 && nIndexDec == -1)
383 )
384 {
385 aBuf.append( OUString::Concat(std::u16string_view(pBuffer + nIndex, nIndexTh - nIndex )) + rNewThSep );
386 nIndex = nIndexTh + rOldThSep.size();
387 }
388 else if( nIndexDec != -1 )
389 {
390 aBuf.append( OUString::Concat(std::u16string_view(pBuffer + nIndex, nIndexDec - nIndex )) + rNewDecSep );
391 nIndex = nIndexDec + rOldDecSep.size();
392 }
393 else
394 {
395 aBuf.append( pBuffer + nIndex );
396 nIndex = -1;
397 }
398 }
399
400 io_rText = aBuf.makeStringAndClear();
401}
402
403void ImplUpdateSeparators( std::u16string_view rOldDecSep, std::u16string_view rNewDecSep,
404 std::u16string_view rOldThSep, std::u16string_view rNewThSep,
405 Edit* pEdit )
406{
407 bool bChangeDec = (rOldDecSep != rNewDecSep);
408 bool bChangeTh = (rOldThSep != rNewThSep );
409
410 if( !(bChangeDec || bChangeTh) )
411 return;
412
413 bool bUpdateMode = pEdit->IsUpdateMode();
414 pEdit->SetUpdateMode( false );
415 OUString aText = pEdit->GetText();
416 ImplUpdateSeparatorString( aText, rOldDecSep, rNewDecSep, rOldThSep, rNewThSep );
417 pEdit->SetText( aText );
418
419 ComboBox* pCombo = dynamic_cast<ComboBox*>(pEdit);
420 if( pCombo )
421 {
422 // update box entries
423 sal_Int32 nEntryCount = pCombo->GetEntryCount();
424 for ( sal_Int32 i=0; i < nEntryCount; i++ )
425 {
426 aText = pCombo->GetEntry( i );
427 void* pEntryData = pCombo->GetEntryData( i );
428 ImplUpdateSeparatorString( aText, rOldDecSep, rNewDecSep, rOldThSep, rNewThSep );
429 pCombo->RemoveEntryAt(i);
430 pCombo->InsertEntry( aText, i );
431 pCombo->SetEntryData( i, pEntryData );
432 }
433 }
434 if( bUpdateMode )
435 pEdit->SetUpdateMode( bUpdateMode );
436}
437
438} // namespace
439
441{
442 mpField = pField;
443 mpLocaleDataWrapper = nullptr;
444 mbReformat = false;
445 mbStrictFormat = false;
446 mbEmptyFieldValue = false;
448}
449
451{
452}
453
455{
456 if ( !mpLocaleDataWrapper )
457 {
459 }
460 return *mpLocaleDataWrapper;
461}
462
465{
466 // just get rid of, the next time it is requested, it will get loaded with the right
467 // language tag
468 mpLocaleDataWrapper.reset();
469}
470
472{
474}
475
477{
478}
479
481{
482 Reformat();
483};
484
486{
487 if ( bStrict != mbStrictFormat )
488 {
489 mbStrictFormat = bStrict;
490 if ( mbStrictFormat )
491 ReformatAll();
492 }
493}
494
495const lang::Locale& FormatterBase::GetLocale() const
496{
497 if ( mpField )
499 else
501}
502
504{
505 if ( mpField )
507 else
509}
510
511void FormatterBase::ImplSetText( const OUString& rText, Selection const * pNewSelection )
512{
513 if ( mpField )
514 {
515 if (pNewSelection)
516 mpField->SetText(rText, *pNewSelection);
517 else
518 {
520 aSel.Min() = aSel.Max();
521 mpField->SetText(rText, aSel);
522 }
523 MarkToBeReformatted( false );
524 }
525}
526
528{
529 if ( mpField )
530 mpField->SetText( OUString() );
531 mbEmptyFieldValue = true;
532}
533
535{
536 return (!mpField || mpField->GetText().isEmpty());
537}
538
539void NumericFormatter::FormatValue(Selection const * pNewSelection)
540{
541 mbFormatting = true;
542 ImplSetText(CreateFieldText(mnLastValue), pNewSelection);
543 mbFormatting = false;
544}
545
546void NumericFormatter::ImplNumericReformat()
547{
548 mnLastValue = GetValue();
549 FormatValue();
550}
551
552NumericFormatter::NumericFormatter(Edit* pEdit)
553 : FormatterBase(pEdit)
554 , mnLastValue(0)
555 , mnMin(0)
556 // a "large" value substantially smaller than SAL_MAX_INT64, to avoid
557 // overflow in computations using this "dummy" value
558 , mnMax(SAL_MAX_INT32)
559 , mbFormatting(false)
560 , mnSpinSize(1)
561 // for fields
562 , mnFirst(mnMin)
563 , mnLast(mnMax)
564 , mnDecimalDigits(0)
565 , mbThousandSep(true)
566{
567 ReformatAll();
568}
569
570NumericFormatter::~NumericFormatter()
571{
572}
573
574void NumericFormatter::SetMin( sal_Int64 nNewMin )
575{
576 mnMin = nNewMin;
577 if ( !IsEmptyFieldValue() )
578 ReformatAll();
579}
580
581void NumericFormatter::SetMax( sal_Int64 nNewMax )
582{
583 mnMax = nNewMax;
584 if ( !IsEmptyFieldValue() )
585 ReformatAll();
586}
587
588void NumericFormatter::SetUseThousandSep( bool bValue )
589{
590 mbThousandSep = bValue;
591 ReformatAll();
592}
593
594void NumericFormatter::SetDecimalDigits( sal_uInt16 nDigits )
595{
596 mnDecimalDigits = nDigits;
597 ReformatAll();
598}
599
600void NumericFormatter::SetValue( sal_Int64 nNewValue )
601{
602 SetUserValue( nNewValue );
603 SetEmptyFieldValueData( false );
604}
605
606OUString NumericFormatter::CreateFieldText( sal_Int64 nValue ) const
607{
608 return ImplGetLocaleDataWrapper().getNum( nValue, GetDecimalDigits(), IsUseThousandSep(), /*ShowTrailingZeros*/true );
609}
610
611void NumericFormatter::ImplSetUserValue( sal_Int64 nNewValue, Selection const * pNewSelection )
612{
613 nNewValue = ClipAgainstMinMax(nNewValue);
614 mnLastValue = nNewValue;
615
616 if ( GetField() )
617 FormatValue(pNewSelection);
618}
619
620void NumericFormatter::SetUserValue( sal_Int64 nNewValue )
621{
622 ImplSetUserValue( nNewValue );
623}
624
625sal_Int64 NumericFormatter::GetValueFromString(const OUString& rStr) const
626{
627 sal_Int64 nTempValue;
628
629 if (ImplNumericGetValue(rStr, nTempValue,
630 GetDecimalDigits(), ImplGetLocaleDataWrapper()))
631 {
632 return ClipAgainstMinMax(nTempValue);
633 }
634 else
635 return mnLastValue;
636}
637
638OUString NumericFormatter::GetValueString() const
639{
641 getNum(GetValue(), GetDecimalDigits(), false, false);
642}
643
644// currently used by online
645void NumericFormatter::SetValueFromString(const OUString& rStr)
646{
647 sal_Int64 nValue;
648
649 if (ImplNumericGetValue(rStr, nValue, GetDecimalDigits(),
650 Application::GetSettings().GetNeutralLocaleDataWrapper()))
651 {
652 ImplNewFieldValue(nValue);
653 }
654 else
655 {
656 SAL_WARN("vcl", "fail to convert the value: " << rStr );
657 }
658}
659
660sal_Int64 NumericFormatter::GetValue() const
661{
662 if (mbFormatting) //don't parse the entry if we're currently formatting what to put in it
663 return mnLastValue;
664
665 return GetField() ? GetValueFromString(GetField()->GetText()) : 0;
666}
667
668sal_Int64 NumericFormatter::Normalize( sal_Int64 nValue ) const
669{
670 return (nValue * ImplPower10( GetDecimalDigits() ) );
671}
672
673sal_Int64 NumericFormatter::Denormalize( sal_Int64 nValue ) const
674{
675 sal_Int64 nFactor = ImplPower10( GetDecimalDigits() );
676
677 if ((nValue < ( SAL_MIN_INT64 + nFactor )) ||
678 (nValue > ( SAL_MAX_INT64 - nFactor )))
679 {
680 return ( nValue / nFactor );
681 }
682
683 if( nValue < 0 )
684 {
685 sal_Int64 nHalf = nFactor / 2;
686 return ((nValue - nHalf) / nFactor );
687 }
688 else
689 {
690 sal_Int64 nHalf = nFactor / 2;
691 return ((nValue + nHalf) / nFactor );
692 }
693}
694
695void NumericFormatter::Reformat()
696{
697 if ( !GetField() )
698 return;
699
700 if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
701 return;
702
703 ImplNumericReformat();
704}
705
706void NumericFormatter::FieldUp()
707{
708 sal_Int64 nValue = GetValue();
709 sal_Int64 nRemainder = nValue % mnSpinSize;
710 if (nValue >= 0)
711 nValue = (nRemainder == 0) ? nValue + mnSpinSize : nValue + mnSpinSize - nRemainder;
712 else
713 nValue = (nRemainder == 0) ? nValue + mnSpinSize : nValue - nRemainder;
714
715 nValue = ClipAgainstMinMax(nValue);
716
717 ImplNewFieldValue( nValue );
718}
719
720void NumericFormatter::FieldDown()
721{
722 sal_Int64 nValue = GetValue();
723 sal_Int64 nRemainder = nValue % mnSpinSize;
724 if (nValue >= 0)
725 nValue = (nRemainder == 0) ? nValue - mnSpinSize : nValue - nRemainder;
726 else
727 nValue = (nRemainder == 0) ? nValue - mnSpinSize : nValue - mnSpinSize - nRemainder;
728
729 nValue = ClipAgainstMinMax(nValue);
730
731 ImplNewFieldValue( nValue );
732}
733
734void NumericFormatter::FieldFirst()
735{
736 ImplNewFieldValue( mnFirst );
737}
738
739void NumericFormatter::FieldLast()
740{
741 ImplNewFieldValue( mnLast );
742}
743
744void NumericFormatter::ImplNewFieldValue( sal_Int64 nNewValue )
745{
746 if ( !GetField() )
747 return;
748
749 // !!! We should check why we do not validate in ImplSetUserValue() if the value was
750 // changed. This should be done there as well since otherwise the call to Modify would not
751 // be allowed. Anyway, the paths from ImplNewFieldValue, ImplSetUserValue, and ImplSetText
752 // should be checked and clearly traced (with comment) in order to find out what happens.
753
754 Selection aSelection = GetField()->GetSelection();
755 aSelection.Normalize();
756 OUString aText = GetField()->GetText();
757 // leave it as is if selected until end
758 if ( static_cast<sal_Int32>(aSelection.Max()) == aText.getLength() )
759 {
760 if ( !aSelection.Len() )
761 aSelection.Min() = SELECTION_MAX;
762 aSelection.Max() = SELECTION_MAX;
763 }
764
765 sal_Int64 nOldLastValue = mnLastValue;
766 ImplSetUserValue( nNewValue, &aSelection );
767 mnLastValue = nOldLastValue;
768
769 // Modify during Edit is only set during KeyInput
770 if ( GetField()->GetText() != aText )
771 {
772 GetField()->SetModifyFlag();
773 GetField()->Modify();
774 }
775}
776
777sal_Int64 NumericFormatter::ClipAgainstMinMax(sal_Int64 nValue) const
778{
779 if (nValue > mnMax)
780 nValue = mnMax;
781 else if (nValue < mnMin)
782 nValue = mnMin;
783 return nValue;
784}
785
786namespace
787{
788 Size calcMinimumSize(const Edit &rSpinField, const NumericFormatter &rFormatter)
789 {
790 OUStringBuffer aBuf;
791 sal_Int32 nTextLen;
792
793 nTextLen = std::u16string_view(OUString::number(rFormatter.GetMin())).size();
794 string::padToLength(aBuf, nTextLen, '9');
795 Size aMinTextSize = rSpinField.CalcMinimumSizeForText(
796 rFormatter.CreateFieldText(OUString::unacquired(aBuf).toInt64()));
797 aBuf.setLength(0);
798
799 nTextLen = std::u16string_view(OUString::number(rFormatter.GetMax())).size();
800 string::padToLength(aBuf, nTextLen, '9');
801 Size aMaxTextSize = rSpinField.CalcMinimumSizeForText(
802 rFormatter.CreateFieldText(OUString::unacquired(aBuf).toInt64()));
803 aBuf.setLength(0);
804
805 Size aRet(std::max(aMinTextSize.Width(), aMaxTextSize.Width()),
806 std::max(aMinTextSize.Height(), aMaxTextSize.Height()));
807
808 OUStringBuffer sBuf("999999999");
809 sal_uInt16 nDigits = rFormatter.GetDecimalDigits();
810 if (nDigits)
811 {
812 sBuf.append('.');
813 string::padToLength(aBuf, aBuf.getLength() + nDigits, '9');
814 }
815 aMaxTextSize = rSpinField.CalcMinimumSizeForText(sBuf.makeStringAndClear());
816 aRet.setWidth( std::min(aRet.Width(), aMaxTextSize.Width()) );
817
818 return aRet;
819 }
820}
821
822NumericBox::NumericBox(vcl::Window* pParent, WinBits nWinStyle)
823 : ComboBox(pParent, nWinStyle)
824 , NumericFormatter(this)
825{
826 Reformat();
827 if ( !(nWinStyle & WB_HIDE ) )
828 Show();
829}
830
831void NumericBox::dispose()
832{
833 ClearField();
835}
836
837Size NumericBox::CalcMinimumSize() const
838{
839 Size aRet(calcMinimumSize(*this, *this));
840
841 if (IsDropDownBox())
842 {
843 Size aComboSugg(ComboBox::CalcMinimumSize());
844 aRet.setWidth( std::max(aRet.Width(), aComboSugg.Width()) );
845 aRet.setHeight( std::max(aRet.Height(), aComboSugg.Height()) );
846 }
847
848 return aRet;
849}
850
851bool NumericBox::PreNotify( NotifyEvent& rNEvt )
852{
853 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
854 {
855 if ( ImplNumericProcessKeyInput( *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
856 return true;
857 }
858
859 return ComboBox::PreNotify( rNEvt );
860}
861
862bool NumericBox::EventNotify( NotifyEvent& rNEvt )
863{
864 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
865 MarkToBeReformatted( false );
866 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
867 {
868 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
869 Reformat();
870 }
871
872 return ComboBox::EventNotify( rNEvt );
873}
874
875void NumericBox::DataChanged( const DataChangedEvent& rDCEvt )
876{
877 ComboBox::DataChanged( rDCEvt );
878
880 {
881 OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
882 OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
883 ImplResetLocaleDataWrapper();
884 OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
885 OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
886 ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
887 ReformatAll();
888 }
889}
890
891void NumericBox::Modify()
892{
893 MarkToBeReformatted( true );
895}
896
897void NumericBox::ImplNumericReformat( const OUString& rStr, sal_Int64& rValue,
898 OUString& rOutStr )
899{
900 if (ImplNumericGetValue(rStr, rValue, GetDecimalDigits(), ImplGetLocaleDataWrapper()))
901 {
902 sal_Int64 nTempVal = ClipAgainstMinMax(rValue);
903 rOutStr = CreateFieldText( nTempVal );
904 }
905}
906
907void NumericBox::ReformatAll()
908{
909 sal_Int64 nValue;
910 OUString aStr;
911 SetUpdateMode( false );
912 sal_Int32 nEntryCount = GetEntryCount();
913 for ( sal_Int32 i=0; i < nEntryCount; i++ )
914 {
915 ImplNumericReformat( GetEntry( i ), nValue, aStr );
916 RemoveEntryAt(i);
917 InsertEntry( aStr, i );
918 }
919 NumericFormatter::Reformat();
920 SetUpdateMode( true );
921}
922
923static bool ImplMetricProcessKeyInput( const KeyEvent& rKEvt,
924 bool bUseThousandSep, const LocaleDataWrapper& rWrapper )
925{
926 // no meaningful strict format; therefore allow all characters
927 return ImplNumericProcessKeyInput( rKEvt, false, bUseThousandSep, rWrapper );
928}
929
930static OUString ImplMetricGetUnitText(std::u16string_view rStr)
931{
932 // fetch unit text
933 OUStringBuffer aStr;
934 for (sal_Int32 i = static_cast<sal_Int32>(rStr.size())-1; i >= 0; --i)
935 {
936 sal_Unicode c = rStr[i];
937 if ( (c == '\'') || (c == '\"') || (c == '%') || (c == 0x2032) || (c == 0x2033) || unicode::isAlpha(c) || unicode::isControl(c) )
938 aStr.insert(0, c);
939 else
940 {
941 if (!aStr.isEmpty())
942 break;
943 }
944 }
945 return aStr.makeStringAndClear();
946}
947
948// #104355# support localized measurements
949
950static OUString ImplMetricToString( FieldUnit rUnit )
951{
952 // return unit's default string (ie, the first one )
953 for (auto const& elem : ImplGetFieldUnits())
954 {
955 if (elem.second == rUnit)
956 return elem.first;
957 }
958
959 return OUString();
960}
961
962namespace
963{
964 FieldUnit StringToMetric(const OUString &rMetricString)
965 {
966 // return FieldUnit
967 OUString aStr = rMetricString.toAsciiLowerCase().replaceAll(" ", "");
968 for (auto const& elem : ImplGetCleanedFieldUnits())
969 {
970 if ( elem.first == aStr )
971 return elem.second;
972 }
973
974 return FieldUnit::NONE;
975 }
976}
977
978static FieldUnit ImplMetricGetUnit(std::u16string_view rStr)
979{
980 OUString aStr = ImplMetricGetUnitText(rStr);
981 return StringToMetric(aStr);
982}
983
984static FieldUnit ImplMap2FieldUnit( MapUnit meUnit, tools::Long& nDecDigits )
985{
986 switch( meUnit )
987 {
988 case MapUnit::Map100thMM :
989 nDecDigits -= 2;
990 return FieldUnit::MM;
991 case MapUnit::Map10thMM :
992 nDecDigits -= 1;
993 return FieldUnit::MM;
994 case MapUnit::MapMM :
995 return FieldUnit::MM;
996 case MapUnit::MapCM :
997 return FieldUnit::CM;
998 case MapUnit::Map1000thInch :
999 nDecDigits -= 3;
1000 return FieldUnit::INCH;
1001 case MapUnit::Map100thInch :
1002 nDecDigits -= 2;
1003 return FieldUnit::INCH;
1004 case MapUnit::Map10thInch :
1005 nDecDigits -= 1;
1006 return FieldUnit::INCH;
1007 case MapUnit::MapInch :
1008 return FieldUnit::INCH;
1009 case MapUnit::MapPoint :
1010 return FieldUnit::POINT;
1011 case MapUnit::MapTwip :
1012 return FieldUnit::TWIP;
1013 default:
1014 OSL_FAIL( "default eInUnit" );
1015 break;
1016 }
1017 return FieldUnit::NONE;
1018}
1019
1020static double nonValueDoubleToValueDouble( double nValue )
1021{
1022 return std::isfinite( nValue ) ? nValue : 0.0;
1023}
1024
1025namespace vcl
1026{
1027 sal_Int64 ConvertValue(sal_Int64 nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits,
1028 FieldUnit eInUnit, FieldUnit eOutUnit)
1029 {
1031 static_cast<double>(nValue), mnBaseValue, nDecDigits, eInUnit, eOutUnit));
1032 sal_Int64 nLong ;
1033
1034 // caution: precision loss in double cast
1035 if ( nDouble <= double(SAL_MIN_INT64) )
1036 nLong = SAL_MIN_INT64;
1037 else if ( nDouble >= double(SAL_MAX_INT64) )
1038 nLong = SAL_MAX_INT64;
1039 else
1040 nLong = static_cast<sal_Int64>( std::round(nDouble) );
1041
1042 return nLong;
1043 }
1044}
1045
1046namespace {
1047
1048bool checkConversionUnits(MapUnit eInUnit, FieldUnit eOutUnit)
1049{
1050 return eOutUnit != FieldUnit::PERCENT
1051 && eOutUnit != FieldUnit::CUSTOM
1052 && eOutUnit != FieldUnit::NONE
1053 && eInUnit != MapUnit::MapPixel
1054 && eInUnit != MapUnit::MapSysFont
1055 && eInUnit != MapUnit::MapAppFont
1056 && eInUnit != MapUnit::MapRelative;
1057}
1058
1059double convertValue( double nValue, tools::Long nDigits, FieldUnit eInUnit, FieldUnit eOutUnit )
1060{
1061 if ( nDigits < 0 )
1062 {
1063 while ( nDigits )
1064 {
1065 nValue += 5;
1066 nValue /= 10;
1067 nDigits++;
1068 }
1069 }
1070 else
1071 {
1072 nValue *= ImplPower10(nDigits);
1073 }
1074
1075 if ( eInUnit != eOutUnit )
1076 {
1077 const o3tl::Length eFrom = FieldToO3tlLength(eInUnit), eTo = FieldToO3tlLength(eOutUnit);
1078 if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
1079 nValue = o3tl::convert(nValue, eFrom, eTo);
1080 }
1081
1082 return nValue;
1083}
1084
1085}
1086
1087namespace vcl
1088{
1089 sal_Int64 ConvertValue( sal_Int64 nValue, sal_uInt16 nDigits,
1090 MapUnit eInUnit, FieldUnit eOutUnit )
1091 {
1092 if ( !checkConversionUnits(eInUnit, eOutUnit) )
1093 {
1094 OSL_FAIL( "invalid parameters" );
1095 return nValue;
1096 }
1097
1098 tools::Long nDecDigits = nDigits;
1099 FieldUnit eFieldUnit = ImplMap2FieldUnit( eInUnit, nDecDigits );
1100
1101 // Avoid sal_Int64 <-> double conversion issues if possible:
1102 if (eFieldUnit == eOutUnit && nDigits == 0)
1103 {
1104 return nValue;
1105 }
1106
1107 return static_cast<sal_Int64>(
1109 convertValue( nValue, nDecDigits, eFieldUnit, eOutUnit ) ) );
1110 }
1111
1112 double ConvertDoubleValue(double nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits,
1113 FieldUnit eInUnit, FieldUnit eOutUnit)
1114 {
1115 if ( eInUnit != eOutUnit )
1116 {
1117 if (eInUnit == FieldUnit::PERCENT && mnBaseValue > 0 && nValue > 0)
1118 {
1119 sal_Int64 nDiv = 100 * ImplPower10(nDecDigits);
1120
1121 if (mnBaseValue != 1)
1123
1124 nValue += nDiv / 2;
1125 nValue /= nDiv;
1126 }
1127 else
1128 {
1131 if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
1132 nValue = o3tl::convert(nValue, eFrom, eTo);
1133 }
1134 }
1135
1136 return nValue;
1137 }
1138
1139 double ConvertDoubleValue(double nValue, sal_uInt16 nDigits,
1140 MapUnit eInUnit, FieldUnit eOutUnit)
1141 {
1142 if ( !checkConversionUnits(eInUnit, eOutUnit) )
1143 {
1144 OSL_FAIL( "invalid parameters" );
1145 return nValue;
1146 }
1147
1148 tools::Long nDecDigits = nDigits;
1149 FieldUnit eFieldUnit = ImplMap2FieldUnit( eInUnit, nDecDigits );
1150
1151 return convertValue(nValue, nDecDigits, eFieldUnit, eOutUnit);
1152 }
1153
1154 double ConvertDoubleValue(double nValue, sal_uInt16 nDigits,
1155 FieldUnit eInUnit, MapUnit eOutUnit)
1156 {
1157 if ( eInUnit == FieldUnit::PERCENT ||
1158 eInUnit == FieldUnit::CUSTOM ||
1159 eInUnit == FieldUnit::NONE ||
1160 eInUnit == FieldUnit::DEGREE ||
1161 eInUnit == FieldUnit::SECOND ||
1162 eInUnit == FieldUnit::MILLISECOND ||
1163 eInUnit == FieldUnit::PIXEL ||
1164 eOutUnit == MapUnit::MapPixel ||
1165 eOutUnit == MapUnit::MapSysFont ||
1166 eOutUnit == MapUnit::MapAppFont ||
1167 eOutUnit == MapUnit::MapRelative )
1168 {
1169 OSL_FAIL( "invalid parameters" );
1170 return nValue;
1171 }
1172
1173 tools::Long nDecDigits = nDigits;
1174 FieldUnit eFieldUnit = ImplMap2FieldUnit( eOutUnit, nDecDigits );
1175
1176 if ( nDecDigits < 0 )
1177 {
1178 nValue *= ImplPower10(-nDecDigits);
1179 }
1180 else
1181 {
1182 nValue /= ImplPower10(nDecDigits);
1183 }
1184
1185 if ( eFieldUnit != eInUnit )
1186 {
1188 const o3tl::Length eTo = FieldToO3tlLength(eFieldUnit, o3tl::Length::invalid);
1189 if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
1190 nValue = o3tl::convert(nValue, eFrom, eTo);
1191 }
1192 return nValue;
1193 }
1194}
1195
1196namespace vcl
1197{
1198 bool TextToValue(const OUString& rStr, double& rValue, sal_Int64 nBaseValue,
1199 sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper, FieldUnit eUnit)
1200 {
1201 // Get value
1202 sal_Int64 nValue;
1203 if ( !ImplNumericGetValue( rStr, nValue, nDecDigits, rLocaleDataWrapper ) )
1204 return false;
1205
1206 // Determine unit
1207 FieldUnit eEntryUnit = ImplMetricGetUnit( rStr );
1208
1209 // Recalculate unit
1210 // caution: conversion to double loses precision
1211 rValue = vcl::ConvertDoubleValue(static_cast<double>(nValue), nBaseValue, nDecDigits, eEntryUnit, eUnit);
1212
1213 return true;
1214 }
1215}
1216
1217void MetricFormatter::ImplMetricReformat( const OUString& rStr, double& rValue, OUString& rOutStr )
1218{
1219 if (!vcl::TextToValue(rStr, rValue, 0, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit))
1220 return;
1221
1222 double nTempVal = rValue;
1223 // caution: precision loss in double cast
1224 if ( nTempVal > GetMax() )
1225 nTempVal = static_cast<double>(GetMax());
1226 else if ( nTempVal < GetMin())
1227 nTempVal = static_cast<double>(GetMin());
1228 rOutStr = CreateFieldText( static_cast<sal_Int64>(nTempVal) );
1229}
1230
1232 : NumericFormatter(pEdit)
1233 , meUnit(FieldUnit::NONE)
1234{
1235}
1236
1238{
1239}
1240
1242{
1243 if (eNewUnit == FieldUnit::MM_100TH)
1244 {
1245 SetDecimalDigits( GetDecimalDigits() + 2 );
1246 meUnit = FieldUnit::MM;
1247 }
1248 else
1249 meUnit = eNewUnit;
1250 ReformatAll();
1251}
1252
1253void MetricFormatter::SetCustomUnitText( const OUString& rStr )
1254{
1255 maCustomUnitText = rStr;
1256 ReformatAll();
1257}
1258
1259void MetricFormatter::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit )
1260{
1261 SetUserValue( nNewValue, eInUnit );
1262}
1263
1264OUString MetricFormatter::CreateFieldText( sal_Int64 nValue ) const
1265{
1266 //whether percent is separated from its number is locale
1267 //specific, pawn it off to icu to decide
1268 if (meUnit == FieldUnit::PERCENT)
1269 {
1270 double dValue = nValue;
1271 dValue /= ImplPower10(GetDecimalDigits());
1272 return unicode::formatPercent(dValue, GetLanguageTag());
1273 }
1274
1275 OUString aStr = NumericFormatter::CreateFieldText( nValue );
1276
1277 if( meUnit == FieldUnit::CUSTOM )
1279 else
1280 {
1281 OUString aSuffix = ImplMetricToString( meUnit );
1282 if (meUnit != FieldUnit::NONE && meUnit != FieldUnit::DEGREE && meUnit != FieldUnit::INCH && meUnit != FieldUnit::FOOT)
1283 aStr += " ";
1284 if (meUnit == FieldUnit::INCH)
1285 {
1286 OUString sDoublePrime = u"\u2033";
1287 if (aSuffix != "\"" && aSuffix != sDoublePrime)
1288 aStr += " ";
1289 else
1290 aSuffix = sDoublePrime;
1291 }
1292 else if (meUnit == FieldUnit::FOOT)
1293 {
1294 OUString sPrime = u"\u2032";
1295 if (aSuffix != "'" && aSuffix != sPrime)
1296 aStr += " ";
1297 else
1298 aSuffix = sPrime;
1299 }
1300
1301 assert(meUnit != FieldUnit::PERCENT);
1302 aStr += aSuffix;
1303 }
1304 return aStr;
1305}
1306
1307void MetricFormatter::SetUserValue( sal_Int64 nNewValue, FieldUnit eInUnit )
1308{
1309 // convert to previously configured units
1310 nNewValue = vcl::ConvertValue( nNewValue, 0, GetDecimalDigits(), eInUnit, meUnit );
1311 NumericFormatter::SetUserValue( nNewValue );
1312}
1313
1314sal_Int64 MetricFormatter::GetValueFromStringUnit(const OUString& rStr, FieldUnit eOutUnit) const
1315{
1316 double nTempValue;
1317 // caution: precision loss in double cast
1318 if (!vcl::TextToValue(rStr, nTempValue, 0, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit))
1319 nTempValue = static_cast<double>(mnLastValue);
1320
1321 // caution: precision loss in double cast
1322 if (nTempValue > mnMax)
1323 nTempValue = static_cast<double>(mnMax);
1324 else if (nTempValue < mnMin)
1325 nTempValue = static_cast<double>(mnMin);
1326
1327 // convert to requested units
1328 return vcl::ConvertValue(static_cast<sal_Int64>(nTempValue), 0, GetDecimalDigits(), meUnit, eOutUnit);
1329}
1330
1331sal_Int64 MetricFormatter::GetValueFromString(const OUString& rStr) const
1332{
1333 return GetValueFromStringUnit(rStr, FieldUnit::NONE);
1334}
1335
1336sal_Int64 MetricFormatter::GetValue( FieldUnit eOutUnit ) const
1337{
1338 return GetField() ? GetValueFromStringUnit(GetField()->GetText(), eOutUnit) : 0;
1339}
1340
1341void MetricFormatter::SetValue( sal_Int64 nValue )
1342{
1343 // Implementation not inline, because it is a virtual Function
1344 SetValue( nValue, FieldUnit::NONE );
1345}
1346
1347void MetricFormatter::SetMin( sal_Int64 nNewMin, FieldUnit eInUnit )
1348{
1349 // convert to requested units
1350 NumericFormatter::SetMin(vcl::ConvertValue(nNewMin, 0, GetDecimalDigits(), eInUnit, meUnit));
1351}
1352
1353sal_Int64 MetricFormatter::GetMin( FieldUnit eOutUnit ) const
1354{
1355 // convert to requested units
1356 return vcl::ConvertValue(NumericFormatter::GetMin(), 0, GetDecimalDigits(), meUnit, eOutUnit);
1357}
1358
1359void MetricFormatter::SetMax( sal_Int64 nNewMax, FieldUnit eInUnit )
1360{
1361 // convert to requested units
1362 NumericFormatter::SetMax(vcl::ConvertValue(nNewMax, 0, GetDecimalDigits(), eInUnit, meUnit));
1363}
1364
1365sal_Int64 MetricFormatter::GetMax( FieldUnit eOutUnit ) const
1366{
1367 // convert to requested units
1368 return vcl::ConvertValue(NumericFormatter::GetMax(), 0, GetDecimalDigits(), meUnit, eOutUnit);
1369}
1370
1372{
1373 if ( !GetField() )
1374 return;
1375
1376 OUString aText = GetField()->GetText();
1377
1378 OUString aStr;
1379 // caution: precision loss in double cast
1380 double nTemp = static_cast<double>(mnLastValue);
1381 ImplMetricReformat( aText, nTemp, aStr );
1382 mnLastValue = static_cast<sal_Int64>(nTemp);
1383
1384 if ( !aStr.isEmpty() )
1385 {
1386 ImplSetText( aStr );
1387 }
1388 else
1389 SetValue( mnLastValue );
1390}
1391
1393{
1394 // convert to requested units
1395 return vcl::ConvertValue(0/*nCorrectedValue*/, 0, GetDecimalDigits(),
1396 meUnit, eOutUnit);
1397}
1398
1400 : SpinField(pParent, nWinStyle, WindowType::METRICFIELD)
1401 , MetricFormatter(this)
1402{
1403 Reformat();
1404}
1405
1407{
1408 ClearField();
1410}
1411
1413{
1414 return calcMinimumSize(*this, *this);
1415}
1416
1417bool MetricField::set_property(const OUString &rKey, const OUString &rValue)
1418{
1419 if (rKey == "digits")
1420 SetDecimalDigits(rValue.toInt32());
1421 else if (rKey == "spin-size")
1422 SetSpinSize(rValue.toInt32());
1423 else
1424 return SpinField::set_property(rKey, rValue);
1425 return true;
1426}
1427
1429{
1430 sal_Int64 nRawMax = GetMax( nNewUnit );
1431 sal_Int64 nMax = Denormalize( nRawMax );
1432 sal_Int64 nMin = Denormalize( GetMin( nNewUnit ) );
1433 sal_Int64 nFirst = Denormalize( GetFirst( nNewUnit ) );
1434 sal_Int64 nLast = Denormalize( GetLast( nNewUnit ) );
1435
1436 MetricFormatter::SetUnit( nNewUnit );
1437
1438 SetMax( Normalize( nMax ), nNewUnit );
1439 SetMin( Normalize( nMin ), nNewUnit );
1440 SetFirst( Normalize( nFirst ), nNewUnit );
1441 SetLast( Normalize( nLast ), nNewUnit );
1442}
1443
1444void MetricField::SetFirst( sal_Int64 nNewFirst, FieldUnit eInUnit )
1445{
1446 // convert
1447 nNewFirst = vcl::ConvertValue(nNewFirst, 0, GetDecimalDigits(), eInUnit, meUnit);
1448 mnFirst = nNewFirst;
1449}
1450
1451sal_Int64 MetricField::GetFirst( FieldUnit eOutUnit ) const
1452{
1453 // convert
1454 return vcl::ConvertValue(mnFirst, 0, GetDecimalDigits(), meUnit, eOutUnit);
1455}
1456
1457void MetricField::SetLast( sal_Int64 nNewLast, FieldUnit eInUnit )
1458{
1459 // convert
1460 nNewLast = vcl::ConvertValue(nNewLast, 0, GetDecimalDigits(), eInUnit, meUnit);
1461 mnLast = nNewLast;
1462}
1463
1464sal_Int64 MetricField::GetLast( FieldUnit eOutUnit ) const
1465{
1466 // convert
1467 return vcl::ConvertValue(mnLast, 0, GetDecimalDigits(), meUnit, eOutUnit);
1468}
1469
1471{
1472 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1473 {
1474 if ( ImplMetricProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1475 return true;
1476 }
1477
1478 return SpinField::PreNotify( rNEvt );
1479}
1480
1482{
1483 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
1484 MarkToBeReformatted( false );
1485 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
1486 {
1487 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1488 Reformat();
1489 }
1490
1491 return SpinField::EventNotify( rNEvt );
1492}
1493
1495{
1496 SpinField::DataChanged( rDCEvt );
1497
1498 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1499 {
1500 OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1501 OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1502 ImplResetLocaleDataWrapper();
1503 OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1504 OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1505 ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
1506 ReformatAll();
1507 }
1508}
1509
1511{
1512 MarkToBeReformatted( true );
1514}
1515
1517{
1518 FieldUp();
1519 SpinField::Up();
1520}
1521
1523{
1524 FieldDown();
1526}
1527
1529{
1530 FieldFirst();
1532}
1533
1535{
1536 FieldLast();
1538}
1539
1541{
1542 SpinField::DumpAsPropertyTree(rJsonWriter);
1543 rJsonWriter.put("min", GetMin());
1544 rJsonWriter.put("max", GetMax());
1545 rJsonWriter.put("unit", FieldUnitToString(GetUnit()));
1547 getNum(GetValue(), GetDecimalDigits(), false, false);
1548 rJsonWriter.put("value", sValue);
1549}
1550
1552{
1554}
1555
1557 : ComboBox(pParent, nWinStyle)
1558 , MetricFormatter(this)
1559{
1560 Reformat();
1561}
1562
1564{
1565 ClearField();
1567}
1568
1570{
1571 Size aRet(calcMinimumSize(*this, *this));
1572
1573 if (IsDropDownBox())
1574 {
1575 Size aComboSugg(ComboBox::CalcMinimumSize());
1576 aRet.setWidth( std::max(aRet.Width(), aComboSugg.Width()) );
1577 aRet.setHeight( std::max(aRet.Height(), aComboSugg.Height()) );
1578 }
1579
1580 return aRet;
1581}
1582
1584{
1585 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1586 {
1587 if ( ImplMetricProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1588 return true;
1589 }
1590
1591 return ComboBox::PreNotify( rNEvt );
1592}
1593
1595{
1596 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
1597 MarkToBeReformatted( false );
1598 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
1599 {
1600 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1601 Reformat();
1602 }
1603
1604 return ComboBox::EventNotify( rNEvt );
1605}
1606
1608{
1609 ComboBox::DataChanged( rDCEvt );
1610
1611 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1612 {
1613 OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1614 OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1615 ImplResetLocaleDataWrapper();
1616 OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1617 OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1618 ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
1619 ReformatAll();
1620 }
1621}
1622
1624{
1625 MarkToBeReformatted( true );
1627}
1628
1630{
1631 double nValue;
1632 OUString aStr;
1633 SetUpdateMode( false );
1634 sal_Int32 nEntryCount = GetEntryCount();
1635 for ( sal_Int32 i=0; i < nEntryCount; i++ )
1636 {
1639 InsertEntry( aStr, i );
1640 }
1642 SetUpdateMode( true );
1643}
1644
1645static bool ImplCurrencyProcessKeyInput( const KeyEvent& rKEvt,
1646 bool bUseThousandSep, const LocaleDataWrapper& rWrapper )
1647{
1648 // no strict format set; therefore allow all characters
1649 return ImplNumericProcessKeyInput( rKEvt, false, bUseThousandSep, rWrapper );
1650}
1651
1652static bool ImplCurrencyGetValue( const OUString& rStr, sal_Int64& rValue,
1653 sal_uInt16 nDecDigits, const LocaleDataWrapper& rWrapper )
1654{
1655 // fetch number
1656 return ImplNumericGetValue( rStr, rValue, nDecDigits, rWrapper, true );
1657}
1658
1659void CurrencyFormatter::ImplCurrencyReformat( const OUString& rStr, OUString& rOutStr )
1660{
1661 sal_Int64 nValue;
1662 if ( !ImplNumericGetValue( rStr, nValue, GetDecimalDigits(), ImplGetLocaleDataWrapper(), true ) )
1663 return;
1664
1665 sal_Int64 nTempVal = nValue;
1666 if ( nTempVal > GetMax() )
1667 nTempVal = GetMax();
1668 else if ( nTempVal < GetMin())
1669 nTempVal = GetMin();
1670 rOutStr = CreateFieldText( nTempVal );
1671}
1672
1673CurrencyFormatter::CurrencyFormatter(Edit* pField)
1674 : NumericFormatter(pField)
1675{
1676}
1677
1678CurrencyFormatter::~CurrencyFormatter()
1679{
1680}
1681
1682void CurrencyFormatter::SetValue( sal_Int64 nNewValue )
1683{
1684 SetUserValue( nNewValue );
1685 SetEmptyFieldValueData( false );
1686}
1687
1688OUString CurrencyFormatter::CreateFieldText( sal_Int64 nValue ) const
1689{
1690 return ImplGetLocaleDataWrapper().getCurr( nValue, GetDecimalDigits(),
1691 ImplGetLocaleDataWrapper().getCurrSymbol(),
1692 IsUseThousandSep() );
1693}
1694
1695sal_Int64 CurrencyFormatter::GetValueFromString(const OUString& rStr) const
1696{
1697 sal_Int64 nTempValue;
1698 if ( ImplCurrencyGetValue( rStr, nTempValue, GetDecimalDigits(), ImplGetLocaleDataWrapper() ) )
1699 {
1700 return ClipAgainstMinMax(nTempValue);
1701 }
1702 else
1703 return mnLastValue;
1704}
1705
1706void CurrencyFormatter::Reformat()
1707{
1708 if ( !GetField() )
1709 return;
1710
1711 OUString aStr;
1712 ImplCurrencyReformat( GetField()->GetText(), aStr );
1713
1714 if ( !aStr.isEmpty() )
1715 {
1716 ImplSetText( aStr );
1717 sal_Int64 nTemp = mnLastValue;
1718 ImplCurrencyGetValue( aStr, nTemp, GetDecimalDigits(), ImplGetLocaleDataWrapper() );
1719 mnLastValue = nTemp;
1720 }
1721 else
1722 SetValue( mnLastValue );
1723}
1724
1725CurrencyField::CurrencyField(vcl::Window* pParent, WinBits nWinStyle)
1726 : SpinField(pParent, nWinStyle)
1727 , CurrencyFormatter(this)
1728{
1729 Reformat();
1730}
1731
1732void CurrencyField::dispose()
1733{
1734 ClearField();
1736}
1737
1738bool CurrencyField::PreNotify( NotifyEvent& rNEvt )
1739{
1740 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1741 {
1742 if ( ImplCurrencyProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1743 return true;
1744 }
1745
1746 return SpinField::PreNotify( rNEvt );
1747}
1748
1749bool CurrencyField::EventNotify( NotifyEvent& rNEvt )
1750{
1751 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
1752 MarkToBeReformatted( false );
1753 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
1754 {
1755 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1756 Reformat();
1757 }
1758
1759 return SpinField::EventNotify( rNEvt );
1760}
1761
1762void CurrencyField::DataChanged( const DataChangedEvent& rDCEvt )
1763{
1764 SpinField::DataChanged( rDCEvt );
1765
1766 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1767 {
1768 OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1769 OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1770 ImplResetLocaleDataWrapper();
1771 OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1772 OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1773 ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
1774 ReformatAll();
1775 }
1776}
1777
1778void CurrencyField::Modify()
1779{
1780 MarkToBeReformatted( true );
1782}
1783
1784void CurrencyField::Up()
1785{
1786 FieldUp();
1787 SpinField::Up();
1788}
1789
1790void CurrencyField::Down()
1791{
1792 FieldDown();
1794}
1795
1796void CurrencyField::First()
1797{
1798 FieldFirst();
1800}
1801
1802void CurrencyField::Last()
1803{
1804 FieldLast();
1806}
1807
1808CurrencyBox::CurrencyBox(vcl::Window* pParent, WinBits nWinStyle)
1809 : ComboBox(pParent, nWinStyle)
1810 , CurrencyFormatter(this)
1811{
1812 Reformat();
1813}
1814
1815void CurrencyBox::dispose()
1816{
1817 ClearField();
1819}
1820
1821bool CurrencyBox::PreNotify( NotifyEvent& rNEvt )
1822{
1823 if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1824 {
1825 if ( ImplCurrencyProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1826 return true;
1827 }
1828
1829 return ComboBox::PreNotify( rNEvt );
1830}
1831
1832bool CurrencyBox::EventNotify( NotifyEvent& rNEvt )
1833{
1834 if ( rNEvt.GetType() == NotifyEventType::GETFOCUS )
1835 MarkToBeReformatted( false );
1836 else if ( rNEvt.GetType() == NotifyEventType::LOSEFOCUS )
1837 {
1838 if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1839 Reformat();
1840 }
1841
1842 return ComboBox::EventNotify( rNEvt );
1843}
1844
1845void CurrencyBox::DataChanged( const DataChangedEvent& rDCEvt )
1846{
1847 ComboBox::DataChanged( rDCEvt );
1848
1849 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1850 {
1851 OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1852 OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1853 ImplResetLocaleDataWrapper();
1854 OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1855 OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1856 ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
1857 ReformatAll();
1858 }
1859}
1860
1861void CurrencyBox::Modify()
1862{
1863 MarkToBeReformatted( true );
1865}
1866
1867void CurrencyBox::ReformatAll()
1868{
1869 OUString aStr;
1870 SetUpdateMode( false );
1871 sal_Int32 nEntryCount = GetEntryCount();
1872 for ( sal_Int32 i=0; i < nEntryCount; i++ )
1873 {
1874 ImplCurrencyReformat( GetEntry( i ), aStr );
1875 RemoveEntryAt(i);
1876 InsertEntry( aStr, i );
1877 }
1878 CurrencyFormatter::Reformat();
1879 SetUpdateMode( true );
1880}
1881
1882/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr o3tl::Length FieldToO3tlLength(FieldUnit eU, o3tl::Length ePixelValue=o3tl::Length::px)
const LanguageTag & GetLanguageTag() const
const LocaleDataWrapper & GetNeutralLocaleDataWrapper() const
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:638
A widget used to choose from a list of items and which has an entry.
Definition: combobox.hxx:39
void RemoveEntryAt(sal_Int32 nPos)
Definition: combobox.cxx:923
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: combobox.cxx:694
void SetEntryData(sal_Int32 nPos, void *pNewData)
Definition: combobox.cxx:1313
virtual void Modify() override
Definition: combobox.cxx:821
sal_Int32 GetEntryCount() const
Definition: combobox.cxx:963
bool IsDropDownBox() const
Definition: combobox.cxx:606
Size CalcMinimumSize() const override
Definition: combobox.cxx:1023
OUString GetEntry(sal_Int32 nPos) const
Definition: combobox.cxx:954
sal_Int32 InsertEntry(const OUString &rStr, sal_Int32 nPos=COMBOBOX_APPEND)
Definition: combobox.cxx:882
void * GetEntryData(sal_Int32 nPos) const
Definition: combobox.cxx:1318
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects.
Definition: combobox.cxx:125
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: combobox.cxx:716
DataChangedEventType GetType() const
Definition: event.hxx:362
AllSettingsFlags GetFlags() const
Definition: event.hxx:363
Definition: edit.hxx:56
virtual void Modify()
Definition: edit.cxx:2320
virtual void SetText(const OUString &rStr) override
Definition: edit.cxx:2551
virtual bool set_property(const OUString &rKey, const OUString &rValue) override
Definition: edit.cxx:183
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: edit.cxx:1906
virtual const Selection & GetSelection() const
Definition: edit.cxx:2474
virtual void DumpAsPropertyTree(tools::JsonWriter &rJsonWriter) override
Dumps itself and potentially its children to a property tree, to be written easily to JSON.
Definition: edit.cxx:2924
virtual Size CalcMinimumSizeForText(const OUString &rString) const
Definition: edit.cxx:2613
virtual OUString GetText() const override
Definition: edit.cxx:2570
SAL_DLLPRIVATE void ImplSetText(const OUString &rText, Selection const *pNewSel=nullptr)
Definition: field.cxx:511
SAL_DLLPRIVATE LocaleDataWrapper & ImplGetLocaleDataWrapper() const
Definition: field.cxx:454
bool mbEmptyFieldValue
Definition: field.hxx:52
const LocaleDataWrapper & GetLocaleDataWrapper() const
Definition: field.cxx:471
bool mbReformat
Definition: field.hxx:50
SAL_DLLPRIVATE void ImplResetLocaleDataWrapper() const
reset the LocaleDataWrapper when the language tag changes
Definition: field.cxx:464
std::unique_ptr< LocaleDataWrapper > mpLocaleDataWrapper
Definition: field.hxx:49
virtual void Reformat()
Definition: field.cxx:476
void SetEmptyFieldValue()
Definition: field.cxx:527
virtual void ReformatAll()
Definition: field.cxx:480
virtual ~FormatterBase()
Definition: field.cxx:450
bool mbEmptyFieldValueEnabled
Definition: field.hxx:53
const css::lang::Locale & GetLocale() const
Definition: field.cxx:495
const LanguageTag & GetLanguageTag() const
Definition: field.cxx:503
VclPtr< Edit > mpField
Definition: field.hxx:47
bool IsEmptyFieldValue() const
Definition: field.cxx:534
FormatterBase(Edit *pField)
Definition: field.cxx:440
void MarkToBeReformatted(bool b)
Definition: field.hxx:75
void SetStrictFormat(bool bStrict)
Definition: field.cxx:485
bool mbStrictFormat
Definition: field.hxx:51
sal_Unicode GetCharCode() const
Definition: event.hxx:56
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:57
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
sal_uInt16 getCurrNegativeFormat() const
const OUString & getNumThousandSep() const
const OUString & getNumDecimalSepAlt() const
const OUString & getNumDecimalSep() const
MetricBox(vcl::Window *pParent, WinBits nWinStyle)
Definition: field.cxx:1556
virtual Size CalcMinimumSize() const override
Definition: field.cxx:1569
virtual void Modify() override
Definition: field.cxx:1623
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: field.cxx:1583
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: field.cxx:1607
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects.
Definition: field.cxx:1563
virtual void ReformatAll() override
Definition: field.cxx:1629
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: field.cxx:1594
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: field.cxx:1470
virtual bool set_property(const OUString &rKey, const OUString &rValue) override
Definition: field.cxx:1417
virtual void DumpAsPropertyTree(tools::JsonWriter &) override
Dumps itself and potentially its children to a property tree, to be written easily to JSON.
Definition: field.cxx:1540
sal_Int64 GetFirst(FieldUnit eOutUnit) const
Definition: field.cxx:1451
virtual void Down() override
Definition: field.cxx:1522
virtual void First() override
Definition: field.cxx:1528
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects.
Definition: field.cxx:1406
virtual void Last() override
Definition: field.cxx:1534
MetricField(vcl::Window *pParent, WinBits nWinStyle)
Definition: field.cxx:1399
virtual FactoryFunction GetUITestFactory() const override
Definition: field.cxx:1551
virtual void SetUnit(FieldUnit meUnit) override
Definition: field.cxx:1428
sal_Int64 GetLast(FieldUnit eOutUnit) const
Definition: field.cxx:1464
virtual Size CalcMinimumSize() const override
Definition: field.cxx:1412
void SetLast(sal_Int64 nNewLast, FieldUnit eInUnit)
Definition: field.cxx:1457
void SetFirst(sal_Int64 nNewFirst, FieldUnit eInUnit)
Definition: field.cxx:1444
virtual void Modify() override
Definition: field.cxx:1510
virtual void Up() override
Definition: field.cxx:1516
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: field.cxx:1494
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: field.cxx:1481
sal_Int64 GetValueFromStringUnit(const OUString &rStr, FieldUnit eOutUnit) const
Definition: field.cxx:1314
FieldUnit meUnit
Definition: field.hxx:194
void SetMax(sal_Int64 nNewMax, FieldUnit eInUnit)
Definition: field.cxx:1359
virtual sal_Int64 GetValueFromString(const OUString &rStr) const override
Definition: field.cxx:1331
virtual OUString CreateFieldText(sal_Int64 nValue) const override
Definition: field.cxx:1264
virtual ~MetricFormatter() override
Definition: field.cxx:1237
SAL_DLLPRIVATE void ImplMetricReformat(const OUString &rStr, double &rValue, OUString &rOutStr)
Definition: field.cxx:1217
MetricFormatter(Edit *pEdit)
Definition: field.cxx:1231
FieldUnit GetUnit() const
Definition: field.hxx:171
sal_Int64 GetMin(FieldUnit eOutUnit) const
Definition: field.cxx:1353
virtual void Reformat() override
Definition: field.cxx:1371
sal_Int64 GetValue(FieldUnit eOutUnit) const
Definition: field.cxx:1336
OUString maCustomUnitText
Definition: field.hxx:204
sal_Int64 GetCorrectedValue(FieldUnit eOutUnit) const
Definition: field.cxx:1392
void SetCustomUnitText(const OUString &rStr)
Definition: field.cxx:1253
virtual void SetUnit(FieldUnit meUnit)
Definition: field.cxx:1241
void SetMin(sal_Int64 nNewMin, FieldUnit eInUnit)
Definition: field.cxx:1347
void SetValue(sal_Int64 nNewValue, FieldUnit eInUnit)
Definition: field.cxx:1259
void SetUserValue(sal_Int64 nNewValue, FieldUnit eInUnit)
Definition: field.cxx:1307
sal_Int64 GetMax(FieldUnit eOutUnit) const
Definition: field.cxx:1365
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:316
NotifyEventType GetType() const
Definition: event.hxx:308
tools::Long Min() const
tools::Long Len() const
void Normalize()
tools::Long Max() const
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
virtual void Last()
Definition: spinfld.cxx:374
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:485
virtual void First()
Definition: spinfld.cxx:369
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: spinfld.cxx:836
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:858
virtual void Down()
Definition: spinfld.cxx:364
virtual void Up()
Definition: spinfld.cxx:359
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects.
Definition: spinfld.cxx:352
void put(std::u16string_view pPropName, const OUString &rPropValue)
static OUString formatPercent(double dNumber, const LanguageTag &rLangTag)
static bool isAlpha(const sal_uInt32 ch)
static bool isControl(const sal_uInt32 ch)
sal_uInt16 GetGroup() const
Definition: keycod.hxx:62
bool IsMod2() const
Definition: keycod.hxx:58
void SetUpdateMode(bool bUpdate)
Definition: window.cxx:2967
bool IsUpdateMode() const
Definition: window2.cxx:1199
const AllSettings & GetSettings() const
Definition: window3.cxx:129
sal_uInt16 mnBaseValue
virtual void SetValue(tools::Long nNew) override
float u
static OUString ImplMetricToString(FieldUnit rUnit)
Definition: field.cxx:950
static OUString ImplMetricGetUnitText(std::u16string_view rStr)
Definition: field.cxx:930
static bool ImplCurrencyProcessKeyInput(const KeyEvent &rKEvt, bool bUseThousandSep, const LocaleDataWrapper &rWrapper)
Definition: field.cxx:1645
static bool ImplCurrencyGetValue(const OUString &rStr, sal_Int64 &rValue, sal_uInt16 nDecDigits, const LocaleDataWrapper &rWrapper)
Definition: field.cxx:1652
static bool ImplMetricProcessKeyInput(const KeyEvent &rKEvt, bool bUseThousandSep, const LocaleDataWrapper &rWrapper)
Definition: field.cxx:923
static double nonValueDoubleToValueDouble(double nValue)
Definition: field.cxx:1020
static FieldUnit ImplMap2FieldUnit(MapUnit meUnit, tools::Long &nDecDigits)
Definition: field.cxx:984
static FieldUnit ImplMetricGetUnit(std::u16string_view rStr)
Definition: field.cxx:978
FieldUnit
sal_Int16 nValue
#define SELECTION_MAX
std::function< std::unique_ptr< UIObject >(vcl::Window *)> FactoryFunction
sal_Int32 nIndex
sal_Int64 n
constexpr sal_uInt16 KEYGROUP_MISC
Definition: keycodes.hxx:41
constexpr sal_uInt16 KEYGROUP_FKEYS
Definition: keycodes.hxx:39
constexpr sal_uInt16 KEYGROUP_CURSOR
Definition: keycodes.hxx:40
#define SAL_WARN(area, stream)
MapUnit
aStr
aBuf
NONE
int i
sal_Int64 toInt64(std::u16string_view str, sal_Int16 radix=10)
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
long Long
bool TextToValue(const OUString &rStr, double &rValue, sal_Int64 nBaseValue, sal_uInt16 nDecDigits, const LocaleDataWrapper &rLocaleDataWrapper, FieldUnit eUnit)
Definition: field.cxx:1198
double ConvertDoubleValue(double nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, FieldUnit eInUnit, FieldUnit eOutUnit)
Definition: field.cxx:1112
sal_Int64 ConvertValue(sal_Int64 nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, FieldUnit eInUnit, FieldUnit eOutUnit)
Definition: field.cxx:1027
const char GetValue[]
const FieldUnitStringList & ImplGetFieldUnits()
Definition: svdata.cxx:266
const FieldUnitStringList & ImplGetCleanedFieldUnits()
Definition: svdata.cxx:296
#define SAL_MAX_INT64
#define SAL_MAX_INT32
#define SAL_MIN_INT64
sal_uInt16 sal_Unicode
sal_Int64 WinBits
Definition: wintypes.hxx:109
WindowType
Definition: wintypes.hxx:27
WinBits const WB_HIDE
Definition: wintypes.hxx:160