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