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