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  {
460  }
461  return *mpLocaleDataWrapper;
462 }
463 
466 {
467  // just get rid of, the next time it is requested, it will get loaded with the right
468  // language tag
469  mpLocaleDataWrapper.reset();
470 }
471 
473 {
474  return ImplGetLocaleDataWrapper();
475 }
476 
478 {
479 }
480 
482 {
483  Reformat();
484 };
485 
486 void FormatterBase::SetStrictFormat( bool bStrict )
487 {
488  if ( bStrict != mbStrictFormat )
489  {
490  mbStrictFormat = bStrict;
491  if ( mbStrictFormat )
492  ReformatAll();
493  }
494 }
495 
496 const lang::Locale& FormatterBase::GetLocale() const
497 {
498  if ( mpField )
500  else
502 }
503 
505 {
506  if ( mpField )
507  return mpField->GetSettings().GetLanguageTag();
508  else
510 }
511 
512 void FormatterBase::ImplSetText( const OUString& rText, Selection const * pNewSelection )
513 {
514  if ( mpField )
515  {
516  if (pNewSelection)
517  mpField->SetText(rText, *pNewSelection);
518  else
519  {
520  Selection aSel = mpField->GetSelection();
521  aSel.Min() = aSel.Max();
522  mpField->SetText(rText, aSel);
523  }
524  MarkToBeReformatted( false );
525  }
526 }
527 
529 {
530  if ( mpField )
531  mpField->SetText( OUString() );
532  mbEmptyFieldValue = true;
533 }
534 
536 {
537  return (!mpField || mpField->GetText().isEmpty());
538 }
539 
540 void NumericFormatter::FormatValue(Selection const * pNewSelection)
541 {
542  mbFormatting = true;
543  ImplSetText(CreateFieldText(mnLastValue), pNewSelection);
544  mbFormatting = false;
545 }
546 
548 {
549  mnLastValue = GetValue();
550  FormatValue();
551 }
552 
554  : FormatterBase(pEdit)
555  , mnLastValue(0)
556  , mnMin(0)
557  // a "large" value substantially smaller than SAL_MAX_INT64, to avoid
558  // overflow in computations using this "dummy" value
559  , mnMax(SAL_MAX_INT32)
560  , mbFormatting(false)
561  , mnSpinSize(1)
562  // for fields
563  , mnFirst(mnMin)
564  , mnLast(mnMax)
565  , mnDecimalDigits(0)
566  , mbThousandSep(true)
567 {
568  ReformatAll();
569 }
570 
572 {
573 }
574 
575 void NumericFormatter::SetMin( sal_Int64 nNewMin )
576 {
577  mnMin = nNewMin;
578  if ( !IsEmptyFieldValue() )
579  ReformatAll();
580 }
581 
582 void NumericFormatter::SetMax( sal_Int64 nNewMax )
583 {
584  mnMax = nNewMax;
585  if ( !IsEmptyFieldValue() )
586  ReformatAll();
587 }
588 
590 {
591  mbThousandSep = bValue;
592  ReformatAll();
593 }
594 
595 void NumericFormatter::SetDecimalDigits( sal_uInt16 nDigits )
596 {
597  mnDecimalDigits = nDigits;
598  ReformatAll();
599 }
600 
601 void NumericFormatter::SetValue( sal_Int64 nNewValue )
602 {
603  SetUserValue( nNewValue );
604  SetEmptyFieldValueData( false );
605 }
606 
607 OUString NumericFormatter::CreateFieldText( sal_Int64 nValue ) const
608 {
609  return ImplGetLocaleDataWrapper().getNum( nValue, GetDecimalDigits(), IsUseThousandSep(), /*ShowTrailingZeros*/true );
610 }
611 
612 void NumericFormatter::ImplSetUserValue( sal_Int64 nNewValue, Selection const * pNewSelection )
613 {
614  nNewValue = ClipAgainstMinMax(nNewValue);
615  mnLastValue = nNewValue;
616 
617  if ( GetField() )
618  FormatValue(pNewSelection);
619 }
620 
621 void NumericFormatter::SetUserValue( sal_Int64 nNewValue )
622 {
623  ImplSetUserValue( nNewValue );
624 }
625 
626 sal_Int64 NumericFormatter::GetValueFromString(const OUString& rStr) const
627 {
628  sal_Int64 nTempValue;
629 
630  if (ImplNumericGetValue(rStr, nTempValue,
632  {
633  return ClipAgainstMinMax(nTempValue);
634  }
635  else
636  return mnLastValue;
637 }
638 
640 {
642  getNum(GetValue(), GetDecimalDigits(), false, false);
643 }
644 
645 // currently used by online
646 void NumericFormatter::SetValueFromString(const OUString& rStr)
647 {
648  sal_Int64 nValue;
649 
650  if (ImplNumericGetValue(rStr, nValue, GetDecimalDigits(),
651  Application::GetSettings().GetNeutralLocaleDataWrapper()))
652  {
653  ImplNewFieldValue(nValue);
654  }
655  else
656  {
657  SAL_WARN("vcl", "fail to convert the value: " << rStr );
658  }
659 }
660 
661 sal_Int64 NumericFormatter::GetValue() const
662 {
663  if (mbFormatting) //don't parse the entry if we're currently formatting what to put in it
664  return mnLastValue;
665 
666  return GetField() ? GetValueFromString(GetField()->GetText()) : 0;
667 }
668 
669 sal_Int64 NumericFormatter::Normalize( sal_Int64 nValue ) const
670 {
671  return (nValue * ImplPower10( GetDecimalDigits() ) );
672 }
673 
674 sal_Int64 NumericFormatter::Denormalize( sal_Int64 nValue ) const
675 {
676  sal_Int64 nFactor = ImplPower10( GetDecimalDigits() );
677 
678  if ((nValue < ( SAL_MIN_INT64 + nFactor )) ||
679  (nValue > ( SAL_MAX_INT64 - nFactor )))
680  {
681  return ( nValue / nFactor );
682  }
683 
684  if( nValue < 0 )
685  {
686  sal_Int64 nHalf = nFactor / 2;
687  return ((nValue - nHalf) / nFactor );
688  }
689  else
690  {
691  sal_Int64 nHalf = nFactor / 2;
692  return ((nValue + nHalf) / nFactor );
693  }
694 }
695 
697 {
698  if ( !GetField() )
699  return;
700 
701  if ( GetField()->GetText().isEmpty() && ImplGetEmptyFieldValue() )
702  return;
703 
705 }
706 
708 {
709  sal_Int64 nValue = GetValue();
710  sal_Int64 nRemainder = nValue % mnSpinSize;
711  if (nValue >= 0)
712  nValue = (nRemainder == 0) ? nValue + mnSpinSize : nValue + mnSpinSize - nRemainder;
713  else
714  nValue = (nRemainder == 0) ? nValue + mnSpinSize : nValue - nRemainder;
715 
716  nValue = ClipAgainstMinMax(nValue);
717 
718  ImplNewFieldValue( nValue );
719 }
720 
722 {
723  sal_Int64 nValue = GetValue();
724  sal_Int64 nRemainder = nValue % mnSpinSize;
725  if (nValue >= 0)
726  nValue = (nRemainder == 0) ? nValue - mnSpinSize : nValue - nRemainder;
727  else
728  nValue = (nRemainder == 0) ? nValue - mnSpinSize : nValue - mnSpinSize - nRemainder;
729 
730  nValue = ClipAgainstMinMax(nValue);
731 
732  ImplNewFieldValue( nValue );
733 }
734 
736 {
738 }
739 
741 {
743 }
744 
745 void NumericFormatter::ImplNewFieldValue( sal_Int64 nNewValue )
746 {
747  if ( !GetField() )
748  return;
749 
750  // !!! We should check why we do not validate in ImplSetUserValue() if the value was
751  // changed. This should be done there as well since otherwise the call to Modify would not
752  // be allowed. Anyway, the paths from ImplNewFieldValue, ImplSetUserValue, and ImplSetText
753  // should be checked and clearly traced (with comment) in order to find out what happens.
754 
755  Selection aSelection = GetField()->GetSelection();
756  aSelection.Justify();
757  OUString aText = GetField()->GetText();
758  // leave it as is if selected until end
759  if ( static_cast<sal_Int32>(aSelection.Max()) == aText.getLength() )
760  {
761  if ( !aSelection.Len() )
762  aSelection.Min() = SELECTION_MAX;
763  aSelection.Max() = SELECTION_MAX;
764  }
765 
766  sal_Int64 nOldLastValue = mnLastValue;
767  ImplSetUserValue( nNewValue, &aSelection );
768  mnLastValue = nOldLastValue;
769 
770  // Modify during Edit is only set during KeyInput
771  if ( GetField()->GetText() != aText )
772  {
773  GetField()->SetModifyFlag();
774  GetField()->Modify();
775  }
776 }
777 
778 sal_Int64 NumericFormatter::ClipAgainstMinMax(sal_Int64 nValue) const
779 {
780  if (nValue > mnMax)
781  nValue = mnMax;
782  else if (nValue < mnMin)
783  nValue = mnMin;
784  return nValue;
785 }
786 
787 namespace
788 {
789  Size calcMinimumSize(const Edit &rSpinField, const NumericFormatter &rFormatter)
790  {
791  OUStringBuffer aBuf;
792  sal_Int32 nTextLen;
793 
794  nTextLen = OUString(OUString::number(rFormatter.GetMin())).getLength();
795  string::padToLength(aBuf, nTextLen, '9');
796  Size aMinTextSize = rSpinField.CalcMinimumSizeForText(
797  rFormatter.CreateFieldText(aBuf.toString().toInt64()));
798  aBuf.setLength(0);
799 
800  nTextLen = OUString(OUString::number(rFormatter.GetMax())).getLength();
801  string::padToLength(aBuf, nTextLen, '9');
802  Size aMaxTextSize = rSpinField.CalcMinimumSizeForText(
803  rFormatter.CreateFieldText(aBuf.toString().toInt64()));
804  aBuf.setLength(0);
805 
806  Size aRet(std::max(aMinTextSize.Width(), aMaxTextSize.Width()),
807  std::max(aMinTextSize.Height(), aMaxTextSize.Height()));
808 
809  OUStringBuffer sBuf("999999999");
810  sal_uInt16 nDigits = rFormatter.GetDecimalDigits();
811  if (nDigits)
812  {
813  sBuf.append('.');
814  string::padToLength(aBuf, aBuf.getLength() + nDigits, '9');
815  }
816  aMaxTextSize = rSpinField.CalcMinimumSizeForText(sBuf.makeStringAndClear());
817  aRet.setWidth( std::min(aRet.Width(), aMaxTextSize.Width()) );
818 
819  return aRet;
820  }
821 }
822 
823 NumericBox::NumericBox(vcl::Window* pParent, WinBits nWinStyle)
824  : ComboBox(pParent, nWinStyle)
825  , NumericFormatter(this)
826 {
827  Reformat();
828  if ( !(nWinStyle & WB_HIDE ) )
829  Show();
830 }
831 
832 void NumericBox::dispose()
833 {
834  ClearField();
836 }
837 
838 Size NumericBox::CalcMinimumSize() const
839 {
840  Size aRet(calcMinimumSize(*this, *this));
841 
842  if (IsDropDownBox())
843  {
844  Size aComboSugg(ComboBox::CalcMinimumSize());
845  aRet.setWidth( std::max(aRet.Width(), aComboSugg.Width()) );
846  aRet.setHeight( std::max(aRet.Height(), aComboSugg.Height()) );
847  }
848 
849  return aRet;
850 }
851 
852 bool NumericBox::PreNotify( NotifyEvent& rNEvt )
853 {
854  if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
855  {
856  if ( ImplNumericProcessKeyInput( *rNEvt.GetKeyEvent(), IsStrictFormat(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
857  return true;
858  }
859 
860  return ComboBox::PreNotify( rNEvt );
861 }
862 
863 bool NumericBox::EventNotify( NotifyEvent& rNEvt )
864 {
865  if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
866  MarkToBeReformatted( false );
867  else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
868  {
869  if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
870  Reformat();
871  }
872 
873  return ComboBox::EventNotify( rNEvt );
874 }
875 
876 void NumericBox::DataChanged( const DataChangedEvent& rDCEvt )
877 {
878  ComboBox::DataChanged( rDCEvt );
879 
880  if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
881  {
882  OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
883  OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
884  ImplResetLocaleDataWrapper();
885  OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
886  OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
887  ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
888  ReformatAll();
889  }
890 }
891 
892 void NumericBox::Modify()
893 {
894  MarkToBeReformatted( true );
896 }
897 
898 void NumericBox::ImplNumericReformat( const OUString& rStr, sal_Int64& rValue,
899  OUString& rOutStr )
900 {
901  if (ImplNumericGetValue(rStr, rValue, GetDecimalDigits(), ImplGetLocaleDataWrapper()))
902  {
903  sal_Int64 nTempVal = ClipAgainstMinMax(rValue);
904  rOutStr = CreateFieldText( nTempVal );
905  }
906 }
907 
908 void NumericBox::ReformatAll()
909 {
910  sal_Int64 nValue;
911  OUString aStr;
912  SetUpdateMode( false );
913  sal_Int32 nEntryCount = GetEntryCount();
914  for ( sal_Int32 i=0; i < nEntryCount; i++ )
915  {
916  ImplNumericReformat( GetEntry( i ), nValue, aStr );
917  RemoveEntryAt(i);
918  InsertEntry( aStr, i );
919  }
921  SetUpdateMode( true );
922 }
923 
924 static bool ImplMetricProcessKeyInput( const KeyEvent& rKEvt,
925  bool bUseThousandSep, const LocaleDataWrapper& rWrapper )
926 {
927  // no meaningful strict format; therefore allow all characters
928  return ImplNumericProcessKeyInput( rKEvt, false, bUseThousandSep, rWrapper );
929 }
930 
931 static OUString ImplMetricGetUnitText(const OUString& rStr)
932 {
933  // fetch unit text
934  OUStringBuffer aStr;
935  for (sal_Int32 i = rStr.getLength()-1; i >= 0; --i)
936  {
937  sal_Unicode c = rStr[i];
938  if ( (c == '\'') || (c == '\"') || (c == '%') || (c == 0x2032) || (c == 0x2033) || unicode::isAlpha(c) || unicode::isControl(c) )
939  aStr.insert(0, c);
940  else
941  {
942  if (!aStr.isEmpty())
943  break;
944  }
945  }
946  return aStr.makeStringAndClear();
947 }
948 
949 // #104355# support localized measurements
950 
951 static OUString ImplMetricToString( FieldUnit rUnit )
952 {
953  // return unit's default string (ie, the first one )
954  for (auto const& elem : ImplGetFieldUnits())
955  {
956  if (elem.second == rUnit)
957  return elem.first;
958  }
959 
960  return OUString();
961 }
962 
963 namespace vcl
964 {
965  FieldUnit StringToMetric(const OUString &rMetricString)
966  {
967  // return FieldUnit
968  OUString aStr = rMetricString.toAsciiLowerCase().replaceAll(" ", "");
969  for (auto const& elem : ImplGetCleanedFieldUnits())
970  {
971  if ( elem.first == aStr )
972  return elem.second;
973  }
974 
975  return FieldUnit::NONE;
976  }
977 }
978 
979 static FieldUnit ImplMetricGetUnit(const OUString& rStr)
980 {
981  OUString aStr = ImplMetricGetUnitText(rStr);
982  return vcl::StringToMetric(aStr);
983 }
984 
985 static FieldUnit ImplMap2FieldUnit( MapUnit meUnit, tools::Long& nDecDigits )
986 {
987  switch( meUnit )
988  {
989  case MapUnit::Map100thMM :
990  nDecDigits -= 2;
991  return FieldUnit::MM;
992  case MapUnit::Map10thMM :
993  nDecDigits -= 1;
994  return FieldUnit::MM;
995  case MapUnit::MapMM :
996  return FieldUnit::MM;
997  case MapUnit::MapCM :
998  return FieldUnit::CM;
999  case MapUnit::Map1000thInch :
1000  nDecDigits -= 3;
1001  return FieldUnit::INCH;
1002  case MapUnit::Map100thInch :
1003  nDecDigits -= 2;
1004  return FieldUnit::INCH;
1005  case MapUnit::Map10thInch :
1006  nDecDigits -= 1;
1007  return FieldUnit::INCH;
1008  case MapUnit::MapInch :
1009  return FieldUnit::INCH;
1010  case MapUnit::MapPoint :
1011  return FieldUnit::POINT;
1012  case MapUnit::MapTwip :
1013  return FieldUnit::TWIP;
1014  default:
1015  OSL_FAIL( "default eInUnit" );
1016  break;
1017  }
1018  return FieldUnit::NONE;
1019 }
1020 
1021 static double nonValueDoubleToValueDouble( double nValue )
1022 {
1023  return std::isfinite( nValue ) ? nValue : 0.0;
1024 }
1025 
1026 namespace vcl
1027 {
1028  sal_Int64 ConvertValue(sal_Int64 nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits,
1029  FieldUnit eInUnit, FieldUnit eOutUnit)
1030  {
1032  static_cast<double>(nValue), mnBaseValue, nDecDigits, eInUnit, eOutUnit));
1033  sal_Int64 nLong ;
1034 
1035  // caution: precision loss in double cast
1036  if ( nDouble <= double(SAL_MIN_INT64) )
1037  nLong = SAL_MIN_INT64;
1038  else if ( nDouble >= double(SAL_MAX_INT64) )
1039  nLong = SAL_MAX_INT64;
1040  else
1041  nLong = static_cast<sal_Int64>( std::round(nDouble) );
1042 
1043  return nLong;
1044  }
1045 }
1046 
1047 namespace {
1048 
1049 bool checkConversionUnits(MapUnit eInUnit, FieldUnit eOutUnit)
1050 {
1051  return eOutUnit != FieldUnit::PERCENT
1052  && eOutUnit != FieldUnit::CUSTOM
1053  && eOutUnit != FieldUnit::NONE
1054  && eInUnit != MapUnit::MapPixel
1055  && eInUnit != MapUnit::MapSysFont
1056  && eInUnit != MapUnit::MapAppFont
1057  && eInUnit != MapUnit::MapRelative;
1058 }
1059 
1060 double convertValue( double nValue, tools::Long nDigits, FieldUnit eInUnit, FieldUnit eOutUnit )
1061 {
1062  if ( nDigits < 0 )
1063  {
1064  while ( nDigits )
1065  {
1066  nValue += 5;
1067  nValue /= 10;
1068  nDigits++;
1069  }
1070  }
1071  else
1072  {
1073  nValue *= ImplPower10(nDigits);
1074  }
1075 
1076  if ( eInUnit != eOutUnit )
1077  {
1078  const o3tl::Length eFrom = FieldToO3tlLength(eInUnit), eTo = FieldToO3tlLength(eOutUnit);
1079  if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
1080  nValue = o3tl::convert(nValue, eFrom, eTo);
1081  }
1082 
1083  return nValue;
1084 }
1085 
1086 }
1087 
1088 namespace vcl
1089 {
1090  sal_Int64 ConvertValue( sal_Int64 nValue, sal_uInt16 nDigits,
1091  MapUnit eInUnit, FieldUnit eOutUnit )
1092  {
1093  if ( !checkConversionUnits(eInUnit, eOutUnit) )
1094  {
1095  OSL_FAIL( "invalid parameters" );
1096  return nValue;
1097  }
1098 
1099  tools::Long nDecDigits = nDigits;
1100  FieldUnit eFieldUnit = ImplMap2FieldUnit( eInUnit, nDecDigits );
1101 
1102  // Avoid sal_Int64 <-> double conversion issues if possible:
1103  if (eFieldUnit == eOutUnit && nDigits == 0)
1104  {
1105  return nValue;
1106  }
1107 
1108  return static_cast<sal_Int64>(
1110  convertValue( nValue, nDecDigits, eFieldUnit, eOutUnit ) ) );
1111  }
1112 
1113  double ConvertDoubleValue(double nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits,
1114  FieldUnit eInUnit, FieldUnit eOutUnit)
1115  {
1116  if ( eInUnit != eOutUnit )
1117  {
1118  if (eInUnit == FieldUnit::PERCENT && mnBaseValue > 0 && nValue > 0)
1119  {
1120  sal_Int64 nDiv = 100 * ImplPower10(nDecDigits);
1121 
1122  if (mnBaseValue != 1)
1123  nValue *= mnBaseValue;
1124 
1125  nValue += nDiv / 2;
1126  nValue /= nDiv;
1127  }
1128  else
1129  {
1130  const o3tl::Length eFrom = FieldToO3tlLength(eInUnit, o3tl::Length::invalid);
1131  const o3tl::Length eTo = FieldToO3tlLength(eOutUnit, o3tl::Length::invalid);
1132  if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
1133  nValue = o3tl::convert(nValue, eFrom, eTo);
1134  }
1135  }
1136 
1137  return nValue;
1138  }
1139 
1140  double ConvertDoubleValue(double nValue, sal_uInt16 nDigits,
1141  MapUnit eInUnit, FieldUnit eOutUnit)
1142  {
1143  if ( !checkConversionUnits(eInUnit, eOutUnit) )
1144  {
1145  OSL_FAIL( "invalid parameters" );
1146  return nValue;
1147  }
1148 
1149  tools::Long nDecDigits = nDigits;
1150  FieldUnit eFieldUnit = ImplMap2FieldUnit( eInUnit, nDecDigits );
1151 
1152  return convertValue(nValue, nDecDigits, eFieldUnit, eOutUnit);
1153  }
1154 
1155  double ConvertDoubleValue(double nValue, sal_uInt16 nDigits,
1156  FieldUnit eInUnit, MapUnit eOutUnit)
1157  {
1158  if ( eInUnit == FieldUnit::PERCENT ||
1159  eInUnit == FieldUnit::CUSTOM ||
1160  eInUnit == FieldUnit::NONE ||
1161  eInUnit == FieldUnit::DEGREE ||
1162  eInUnit == FieldUnit::SECOND ||
1163  eInUnit == FieldUnit::MILLISECOND ||
1164  eInUnit == FieldUnit::PIXEL ||
1165  eOutUnit == MapUnit::MapPixel ||
1166  eOutUnit == MapUnit::MapSysFont ||
1167  eOutUnit == MapUnit::MapAppFont ||
1168  eOutUnit == MapUnit::MapRelative )
1169  {
1170  OSL_FAIL( "invalid parameters" );
1171  return nValue;
1172  }
1173 
1174  tools::Long nDecDigits = nDigits;
1175  FieldUnit eFieldUnit = ImplMap2FieldUnit( eOutUnit, nDecDigits );
1176 
1177  if ( nDecDigits < 0 )
1178  {
1179  nValue *= ImplPower10(-nDecDigits);
1180  }
1181  else
1182  {
1183  nValue /= ImplPower10(nDecDigits);
1184  }
1185 
1186  if ( eFieldUnit != eInUnit )
1187  {
1188  const o3tl::Length eFrom = FieldToO3tlLength(eInUnit, o3tl::Length::invalid);
1189  const o3tl::Length eTo = FieldToO3tlLength(eFieldUnit, o3tl::Length::invalid);
1190  if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
1191  nValue = o3tl::convert(nValue, eFrom, eTo);
1192  }
1193  return nValue;
1194  }
1195 }
1196 
1197 namespace vcl
1198 {
1199  bool TextToValue(const OUString& rStr, double& rValue, sal_Int64 nBaseValue,
1200  sal_uInt16 nDecDigits, const LocaleDataWrapper& rLocaleDataWrapper, FieldUnit eUnit)
1201  {
1202  // Get value
1203  sal_Int64 nValue;
1204  if ( !ImplNumericGetValue( rStr, nValue, nDecDigits, rLocaleDataWrapper ) )
1205  return false;
1206 
1207  // Determine unit
1208  FieldUnit eEntryUnit = ImplMetricGetUnit( rStr );
1209 
1210  // Recalculate unit
1211  // caution: conversion to double loses precision
1212  rValue = vcl::ConvertDoubleValue(static_cast<double>(nValue), nBaseValue, nDecDigits, eEntryUnit, eUnit);
1213 
1214  return true;
1215  }
1216 }
1217 
1218 void MetricFormatter::ImplMetricReformat( const OUString& rStr, double& rValue, OUString& rOutStr )
1219 {
1221  return;
1222 
1223  double nTempVal = rValue;
1224  // caution: precision loss in double cast
1225  if ( nTempVal > GetMax() )
1226  nTempVal = static_cast<double>(GetMax());
1227  else if ( nTempVal < GetMin())
1228  nTempVal = static_cast<double>(GetMin());
1229  rOutStr = CreateFieldText( static_cast<sal_Int64>(nTempVal) );
1230 }
1231 
1233  : NumericFormatter(pEdit)
1234  , meUnit(FieldUnit::NONE)
1235 {
1236 }
1237 
1239 {
1240 }
1241 
1243 {
1244  if (eNewUnit == FieldUnit::MM_100TH)
1245  {
1247  meUnit = FieldUnit::MM;
1248  }
1249  else
1250  meUnit = eNewUnit;
1251  ReformatAll();
1252 }
1253 
1254 void MetricFormatter::SetCustomUnitText( const OUString& rStr )
1255 {
1256  maCustomUnitText = rStr;
1257  ReformatAll();
1258 }
1259 
1260 void MetricFormatter::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit )
1261 {
1262  SetUserValue( nNewValue, eInUnit );
1263 }
1264 
1265 OUString MetricFormatter::CreateFieldText( sal_Int64 nValue ) const
1266 {
1267  //whether percent is separated from its number is locale
1268  //specific, pawn it off to icu to decide
1269  if (meUnit == FieldUnit::PERCENT)
1270  {
1271  double dValue = nValue;
1272  dValue /= ImplPower10(GetDecimalDigits());
1273  return unicode::formatPercent(dValue, GetLanguageTag());
1274  }
1275 
1276  OUString aStr = NumericFormatter::CreateFieldText( nValue );
1277 
1278  if( meUnit == FieldUnit::CUSTOM )
1279  aStr += maCustomUnitText;
1280  else
1281  {
1282  OUString aSuffix = ImplMetricToString( meUnit );
1283  if (meUnit != FieldUnit::NONE && meUnit != FieldUnit::DEGREE && meUnit != FieldUnit::INCH && meUnit != FieldUnit::FOOT)
1284  aStr += " ";
1285  if (meUnit == FieldUnit::INCH)
1286  {
1287  OUString sDoublePrime = u"\u2033";
1288  if (aSuffix != "\"" && aSuffix != sDoublePrime)
1289  aStr += " ";
1290  else
1291  aSuffix = sDoublePrime;
1292  }
1293  else if (meUnit == FieldUnit::FOOT)
1294  {
1295  OUString sPrime = u"\u2032";
1296  if (aSuffix != "'" && aSuffix != sPrime)
1297  aStr += " ";
1298  else
1299  aSuffix = sPrime;
1300  }
1301 
1302  assert(meUnit != FieldUnit::PERCENT);
1303  aStr += aSuffix;
1304  }
1305  return aStr;
1306 }
1307 
1308 void MetricFormatter::SetUserValue( sal_Int64 nNewValue, FieldUnit eInUnit )
1309 {
1310  // convert to previously configured units
1311  nNewValue = vcl::ConvertValue( nNewValue, 0, GetDecimalDigits(), eInUnit, meUnit );
1312  NumericFormatter::SetUserValue( nNewValue );
1313 }
1314 
1315 sal_Int64 MetricFormatter::GetValueFromStringUnit(const OUString& rStr, FieldUnit eOutUnit) const
1316 {
1317  double nTempValue;
1318  // caution: precision loss in double cast
1319  if (!vcl::TextToValue(rStr, nTempValue, 0, GetDecimalDigits(), ImplGetLocaleDataWrapper(), meUnit))
1320  nTempValue = static_cast<double>(mnLastValue);
1321 
1322  // caution: precision loss in double cast
1323  if (nTempValue > mnMax)
1324  nTempValue = static_cast<double>(mnMax);
1325  else if (nTempValue < mnMin)
1326  nTempValue = static_cast<double>(mnMin);
1327 
1328  // convert to requested units
1329  return vcl::ConvertValue(static_cast<sal_Int64>(nTempValue), 0, GetDecimalDigits(), meUnit, eOutUnit);
1330 }
1331 
1332 sal_Int64 MetricFormatter::GetValueFromString(const OUString& rStr) const
1333 {
1334  return GetValueFromStringUnit(rStr, FieldUnit::NONE);
1335 }
1336 
1337 sal_Int64 MetricFormatter::GetValue( FieldUnit eOutUnit ) const
1338 {
1339  return GetField() ? GetValueFromStringUnit(GetField()->GetText(), eOutUnit) : 0;
1340 }
1341 
1342 void MetricFormatter::SetValue( sal_Int64 nValue )
1343 {
1344  // Implementation not inline, because it is a virtual Function
1345  SetValue( nValue, FieldUnit::NONE );
1346 }
1347 
1348 void MetricFormatter::SetMin( sal_Int64 nNewMin, FieldUnit eInUnit )
1349 {
1350  // convert to requested units
1352 }
1353 
1354 sal_Int64 MetricFormatter::GetMin( FieldUnit eOutUnit ) const
1355 {
1356  // convert to requested units
1358 }
1359 
1360 void MetricFormatter::SetMax( sal_Int64 nNewMax, FieldUnit eInUnit )
1361 {
1362  // convert to requested units
1364 }
1365 
1366 sal_Int64 MetricFormatter::GetMax( FieldUnit eOutUnit ) const
1367 {
1368  // convert to requested units
1370 }
1371 
1373 {
1374  if ( !GetField() )
1375  return;
1376 
1377  OUString aText = GetField()->GetText();
1378 
1379  OUString aStr;
1380  // caution: precision loss in double cast
1381  double nTemp = static_cast<double>(mnLastValue);
1382  ImplMetricReformat( aText, nTemp, aStr );
1383  mnLastValue = static_cast<sal_Int64>(nTemp);
1384 
1385  if ( !aStr.isEmpty() )
1386  {
1387  ImplSetText( aStr );
1388  }
1389  else
1390  SetValue( mnLastValue );
1391 }
1392 
1394 {
1395  // convert to requested units
1396  return vcl::ConvertValue(0/*nCorrectedValue*/, 0, GetDecimalDigits(),
1397  meUnit, eOutUnit);
1398 }
1399 
1401  : SpinField(pParent, nWinStyle, WindowType::METRICFIELD)
1402  , MetricFormatter(this)
1403 {
1404  Reformat();
1405 }
1406 
1408 {
1409  ClearField();
1411 }
1412 
1414 {
1415  return calcMinimumSize(*this, *this);
1416 }
1417 
1418 bool MetricField::set_property(const OString &rKey, const OUString &rValue)
1419 {
1420  if (rKey == "digits")
1421  SetDecimalDigits(rValue.toInt32());
1422  else if (rKey == "spin-size")
1423  SetSpinSize(rValue.toInt32());
1424  else
1425  return SpinField::set_property(rKey, rValue);
1426  return true;
1427 }
1428 
1430 {
1431  sal_Int64 nRawMax = GetMax( nNewUnit );
1432  sal_Int64 nMax = Denormalize( nRawMax );
1433  sal_Int64 nMin = Denormalize( GetMin( nNewUnit ) );
1434  sal_Int64 nFirst = Denormalize( GetFirst( nNewUnit ) );
1435  sal_Int64 nLast = Denormalize( GetLast( nNewUnit ) );
1436 
1437  MetricFormatter::SetUnit( nNewUnit );
1438 
1439  SetMax( Normalize( nMax ), nNewUnit );
1440  SetMin( Normalize( nMin ), nNewUnit );
1441  SetFirst( Normalize( nFirst ), nNewUnit );
1442  SetLast( Normalize( nLast ), nNewUnit );
1443 }
1444 
1445 void MetricField::SetFirst( sal_Int64 nNewFirst, FieldUnit eInUnit )
1446 {
1447  // convert
1448  nNewFirst = vcl::ConvertValue(nNewFirst, 0, GetDecimalDigits(), eInUnit, meUnit);
1449  mnFirst = nNewFirst;
1450 }
1451 
1452 sal_Int64 MetricField::GetFirst( FieldUnit eOutUnit ) const
1453 {
1454  // convert
1455  return vcl::ConvertValue(mnFirst, 0, GetDecimalDigits(), meUnit, eOutUnit);
1456 }
1457 
1458 void MetricField::SetLast( sal_Int64 nNewLast, FieldUnit eInUnit )
1459 {
1460  // convert
1461  nNewLast = vcl::ConvertValue(nNewLast, 0, GetDecimalDigits(), eInUnit, meUnit);
1462  mnLast = nNewLast;
1463 }
1464 
1465 sal_Int64 MetricField::GetLast( FieldUnit eOutUnit ) const
1466 {
1467  // convert
1468  return vcl::ConvertValue(mnLast, 0, GetDecimalDigits(), meUnit, eOutUnit);
1469 }
1470 
1472 {
1473  if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1474  {
1476  return true;
1477  }
1478 
1479  return SpinField::PreNotify( rNEvt );
1480 }
1481 
1483 {
1484  if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
1485  MarkToBeReformatted( false );
1486  else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
1487  {
1488  if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1489  Reformat();
1490  }
1491 
1492  return SpinField::EventNotify( rNEvt );
1493 }
1494 
1496 {
1497  SpinField::DataChanged( rDCEvt );
1498 
1499  if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1500  {
1501  OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1502  OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1504  OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1505  OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1506  ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
1507  ReformatAll();
1508  }
1509 }
1510 
1512 {
1513  MarkToBeReformatted( true );
1515 }
1516 
1518 {
1519  FieldUp();
1520  SpinField::Up();
1521 }
1522 
1524 {
1525  FieldDown();
1526  SpinField::Down();
1527 }
1528 
1530 {
1531  FieldFirst();
1532  SpinField::First();
1533 }
1534 
1536 {
1537  FieldLast();
1538  SpinField::Last();
1539 }
1540 
1542 {
1543  SpinField::DumpAsPropertyTree(rJsonWriter);
1544  rJsonWriter.put("min", GetMin());
1545  rJsonWriter.put("max", GetMax());
1546  rJsonWriter.put("unit", FieldUnitToString(GetUnit()));
1548  getNum(GetValue(), GetDecimalDigits(), false, false);
1549  rJsonWriter.put("value", sValue);
1550 }
1551 
1553 {
1555 }
1556 
1558  : ComboBox(pParent, nWinStyle)
1559  , MetricFormatter(this)
1560 {
1561  Reformat();
1562 }
1563 
1565 {
1566  ClearField();
1568 }
1569 
1571 {
1572  Size aRet(calcMinimumSize(*this, *this));
1573 
1574  if (IsDropDownBox())
1575  {
1576  Size aComboSugg(ComboBox::CalcMinimumSize());
1577  aRet.setWidth( std::max(aRet.Width(), aComboSugg.Width()) );
1578  aRet.setHeight( std::max(aRet.Height(), aComboSugg.Height()) );
1579  }
1580 
1581  return aRet;
1582 }
1583 
1585 {
1586  if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1587  {
1589  return true;
1590  }
1591 
1592  return ComboBox::PreNotify( rNEvt );
1593 }
1594 
1596 {
1597  if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
1598  MarkToBeReformatted( false );
1599  else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
1600  {
1601  if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1602  Reformat();
1603  }
1604 
1605  return ComboBox::EventNotify( rNEvt );
1606 }
1607 
1609 {
1610  ComboBox::DataChanged( rDCEvt );
1611 
1612  if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1613  {
1614  OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1615  OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1617  OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1618  OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1619  ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
1620  ReformatAll();
1621  }
1622 }
1623 
1625 {
1626  MarkToBeReformatted( true );
1627  ComboBox::Modify();
1628 }
1629 
1631 {
1632  double nValue;
1633  OUString aStr;
1634  SetUpdateMode( false );
1635  sal_Int32 nEntryCount = GetEntryCount();
1636  for ( sal_Int32 i=0; i < nEntryCount; i++ )
1637  {
1638  ImplMetricReformat( GetEntry( i ), nValue, aStr );
1639  RemoveEntryAt(i);
1640  InsertEntry( aStr, i );
1641  }
1643  SetUpdateMode( true );
1644 }
1645 
1646 static bool ImplCurrencyProcessKeyInput( const KeyEvent& rKEvt,
1647  bool bUseThousandSep, const LocaleDataWrapper& rWrapper )
1648 {
1649  // no strict format set; therefore allow all characters
1650  return ImplNumericProcessKeyInput( rKEvt, false, bUseThousandSep, rWrapper );
1651 }
1652 
1653 static bool ImplCurrencyGetValue( const OUString& rStr, sal_Int64& rValue,
1654  sal_uInt16 nDecDigits, const LocaleDataWrapper& rWrapper )
1655 {
1656  // fetch number
1657  return ImplNumericGetValue( rStr, rValue, nDecDigits, rWrapper, true );
1658 }
1659 
1660 void CurrencyFormatter::ImplCurrencyReformat( const OUString& rStr, OUString& rOutStr )
1661 {
1662  sal_Int64 nValue;
1663  if ( !ImplNumericGetValue( rStr, nValue, GetDecimalDigits(), ImplGetLocaleDataWrapper(), true ) )
1664  return;
1665 
1666  sal_Int64 nTempVal = nValue;
1667  if ( nTempVal > GetMax() )
1668  nTempVal = GetMax();
1669  else if ( nTempVal < GetMin())
1670  nTempVal = GetMin();
1671  rOutStr = CreateFieldText( nTempVal );
1672 }
1673 
1674 CurrencyFormatter::CurrencyFormatter(Edit* pField)
1675  : NumericFormatter(pField)
1676 {
1677 }
1678 
1679 CurrencyFormatter::~CurrencyFormatter()
1680 {
1681 }
1682 
1683 void CurrencyFormatter::SetValue( sal_Int64 nNewValue )
1684 {
1685  SetUserValue( nNewValue );
1686  SetEmptyFieldValueData( false );
1687 }
1688 
1689 OUString CurrencyFormatter::CreateFieldText( sal_Int64 nValue ) const
1690 {
1691  return ImplGetLocaleDataWrapper().getCurr( nValue, GetDecimalDigits(),
1692  ImplGetLocaleDataWrapper().getCurrSymbol(),
1693  IsUseThousandSep() );
1694 }
1695 
1696 sal_Int64 CurrencyFormatter::GetValueFromString(const OUString& rStr) const
1697 {
1698  sal_Int64 nTempValue;
1699  if ( ImplCurrencyGetValue( rStr, nTempValue, GetDecimalDigits(), ImplGetLocaleDataWrapper() ) )
1700  {
1701  return ClipAgainstMinMax(nTempValue);
1702  }
1703  else
1704  return mnLastValue;
1705 }
1706 
1707 void CurrencyFormatter::Reformat()
1708 {
1709  if ( !GetField() )
1710  return;
1711 
1712  OUString aStr;
1713  ImplCurrencyReformat( GetField()->GetText(), aStr );
1714 
1715  if ( !aStr.isEmpty() )
1716  {
1717  ImplSetText( aStr );
1718  sal_Int64 nTemp = mnLastValue;
1719  ImplCurrencyGetValue( aStr, nTemp, GetDecimalDigits(), ImplGetLocaleDataWrapper() );
1720  mnLastValue = nTemp;
1721  }
1722  else
1723  SetValue( mnLastValue );
1724 }
1725 
1726 CurrencyField::CurrencyField(vcl::Window* pParent, WinBits nWinStyle)
1727  : SpinField(pParent, nWinStyle)
1728  , CurrencyFormatter(this)
1729 {
1730  Reformat();
1731 }
1732 
1733 void CurrencyField::dispose()
1734 {
1735  ClearField();
1737 }
1738 
1739 bool CurrencyField::PreNotify( NotifyEvent& rNEvt )
1740 {
1741  if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1742  {
1743  if ( ImplCurrencyProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1744  return true;
1745  }
1746 
1747  return SpinField::PreNotify( rNEvt );
1748 }
1749 
1750 bool CurrencyField::EventNotify( NotifyEvent& rNEvt )
1751 {
1752  if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
1753  MarkToBeReformatted( false );
1754  else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
1755  {
1756  if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1757  Reformat();
1758  }
1759 
1760  return SpinField::EventNotify( rNEvt );
1761 }
1762 
1763 void CurrencyField::DataChanged( const DataChangedEvent& rDCEvt )
1764 {
1765  SpinField::DataChanged( rDCEvt );
1766 
1767  if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1768  {
1769  OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1770  OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1771  ImplResetLocaleDataWrapper();
1772  OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1773  OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1774  ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
1775  ReformatAll();
1776  }
1777 }
1778 
1779 void CurrencyField::Modify()
1780 {
1781  MarkToBeReformatted( true );
1783 }
1784 
1785 void CurrencyField::Up()
1786 {
1787  FieldUp();
1788  SpinField::Up();
1789 }
1790 
1791 void CurrencyField::Down()
1792 {
1793  FieldDown();
1794  SpinField::Down();
1795 }
1796 
1797 void CurrencyField::First()
1798 {
1799  FieldFirst();
1800  SpinField::First();
1801 }
1802 
1803 void CurrencyField::Last()
1804 {
1805  FieldLast();
1806  SpinField::Last();
1807 }
1808 
1809 CurrencyBox::CurrencyBox(vcl::Window* pParent, WinBits nWinStyle)
1810  : ComboBox(pParent, nWinStyle)
1811  , CurrencyFormatter(this)
1812 {
1813  Reformat();
1814 }
1815 
1816 void CurrencyBox::dispose()
1817 {
1818  ClearField();
1820 }
1821 
1822 bool CurrencyBox::PreNotify( NotifyEvent& rNEvt )
1823 {
1824  if ( (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !rNEvt.GetKeyEvent()->GetKeyCode().IsMod2() )
1825  {
1826  if ( ImplCurrencyProcessKeyInput( *rNEvt.GetKeyEvent(), IsUseThousandSep(), ImplGetLocaleDataWrapper() ) )
1827  return true;
1828  }
1829 
1830  return ComboBox::PreNotify( rNEvt );
1831 }
1832 
1833 bool CurrencyBox::EventNotify( NotifyEvent& rNEvt )
1834 {
1835  if ( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
1836  MarkToBeReformatted( false );
1837  else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
1838  {
1839  if ( MustBeReformatted() && (!GetText().isEmpty() || !IsEmptyFieldValueEnabled()) )
1840  Reformat();
1841  }
1842 
1843  return ComboBox::EventNotify( rNEvt );
1844 }
1845 
1846 void CurrencyBox::DataChanged( const DataChangedEvent& rDCEvt )
1847 {
1848  ComboBox::DataChanged( rDCEvt );
1849 
1850  if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::LOCALE) )
1851  {
1852  OUString sOldDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1853  OUString sOldThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1854  ImplResetLocaleDataWrapper();
1855  OUString sNewDecSep = ImplGetLocaleDataWrapper().getNumDecimalSep();
1856  OUString sNewThSep = ImplGetLocaleDataWrapper().getNumThousandSep();
1857  ImplUpdateSeparators( sOldDecSep, sNewDecSep, sOldThSep, sNewThSep, this );
1858  ReformatAll();
1859  }
1860 }
1861 
1862 void CurrencyBox::Modify()
1863 {
1864  MarkToBeReformatted( true );
1865  ComboBox::Modify();
1866 }
1867 
1868 void CurrencyBox::ReformatAll()
1869 {
1870  OUString aStr;
1871  SetUpdateMode( false );
1872  sal_Int32 nEntryCount = GetEntryCount();
1873  for ( sal_Int32 i=0; i < nEntryCount; i++ )
1874  {
1875  ImplCurrencyReformat( GetEntry( i ), aStr );
1876  RemoveEntryAt(i);
1877  InsertEntry( aStr, i );
1878  }
1879  CurrencyFormatter::Reformat();
1880  SetUpdateMode( true );
1881 }
1882 
1883 /* 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:1584
void FieldLast()
Definition: field.cxx:740
virtual bool set_property(const OString &rKey, const OUString &rValue) override
Definition: field.cxx:1418
sal_Int64 GetFirst() const
Definition: field.hxx:108
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:1372
void SetMax(sal_Int64 nNewMax)
Definition: field.cxx:582
bool mbFormatting
Definition: field.hxx:135
virtual sal_Int64 GetValueFromString(const OUString &rStr) const override
Definition: field.cxx:1332
void SetMin(sal_Int64 nNewMin, FieldUnit eInUnit)
Definition: field.cxx:1348
virtual Size CalcMinimumSizeForText(const OUString &rString) const
Definition: edit.cxx:2605
void SetFirst(sal_Int64 nNewFirst, FieldUnit eInUnit)
Definition: field.cxx:1445
FieldUnit StringToMetric(const OUString &rMetricString)
Definition: field.cxx:965
long Long
static const AllSettings & GetSettings()
Gets the application's settings.
Definition: svapp.cxx:733
bool mbThousandSep
Definition: field.hxx:159
static OUString ImplMetricToString(FieldUnit rUnit)
Definition: field.cxx:951
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
SAL_DLLPRIVATE void ImplResetLocaleDataWrapper() const
reset the LocaleDataWrapper when the language tag changes
Definition: field.cxx:465
std::function< std::unique_ptr< UIObject >vcl::Window *)> FactoryFunction
virtual OUString CreateFieldText(sal_Int64 nValue) const
Definition: field.cxx:607
virtual void Last() override
Definition: field.cxx:1535
aBuf
virtual void Modify() override
Definition: field.cxx:1624
constexpr o3tl::Length FieldToO3tlLength(FieldUnit eU, o3tl::Length ePixelValue=o3tl::Length::px)
void SetEmptyFieldValue()
Definition: field.cxx:528
sal_uInt16 GetGroup() const
Definition: keycod.hxx:62
DataChangedEventType GetType() const
Definition: event.hxx:362
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:316
void SetMax(sal_Int64 nNewMax, FieldUnit eInUnit)
Definition: field.cxx:1360
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:2916
sal_Int64 mnLastValue
Definition: field.hxx:132
virtual FactoryFunction GetUITestFactory() const override
Definition: field.cxx:1552
virtual void SetUnit(FieldUnit meUnit)
Definition: field.cxx:1242
bool IsEmptyFieldValueEnabled() const
Definition: field.hxx:90
virtual bool set_property(const OString &rKey, const OUString &rValue) override
Definition: edit.cxx:181
virtual void Up()
Definition: spinfld.cxx:357
std::unique_ptr< LocaleDataWrapper > mpLocaleDataWrapper
Definition: field.hxx:49
static bool ImplMetricProcessKeyInput(const KeyEvent &rKEvt, bool bUseThousandSep, const LocaleDataWrapper &rWrapper)
Definition: field.cxx:924
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: field.cxx:1595
sal_Int64 GetValue() const
Definition: field.cxx:661
bool mbEmptyFieldValueEnabled
Definition: field.hxx:53
void SetStrictFormat(bool bStrict)
Definition: field.cxx:486
bool MustBeReformatted() const
Definition: field.hxx:74
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
SAL_DLLPRIVATE void ImplSetUserValue(sal_Int64 nNewValue, Selection const *pNewSelection=nullptr)
Definition: field.cxx:612
void ClearField()
Definition: field.hxx:66
void SetSpinSize(sal_Int64 nNewSize)
Definition: field.hxx:111
void SetMin(sal_Int64 nNewMin)
Definition: field.cxx:575
NONE
void SetEntryData(sal_Int32 nPos, void *pNewData)
Definition: combobox.cxx:1313
constexpr tools::Long Width() const
OUString GetEntry(sal_Int32 nPos) const
Definition: combobox.cxx:953
static FieldUnit ImplMap2FieldUnit(MapUnit meUnit, tools::Long &nDecDigits)
Definition: field.cxx:985
sal_Int64 WinBits
sal_uInt16 sal_Unicode
Edit * GetField() const
Definition: field.hxx:65
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: spinfld.cxx:350
static FieldUnit ImplMetricGetUnit(const OUString &rStr)
Definition: field.cxx:979
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: combobox.cxx:124
FieldUnit GetUnit() const
Definition: field.hxx:171
OUString maCustomUnitText
Definition: field.hxx:204
bool mbEmptyFieldValue
Definition: field.hxx:52
sal_uInt16 GetDecimalDigits() const
Definition: field.hxx:115
AllSettingsFlags GetFlags() const
Definition: event.hxx:363
virtual void SetModifyFlag()
Definition: edit.cxx:2586
bool IsEmptyFieldValue() const
Definition: field.cxx:535
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:745
Definition: edit.hxx:55
virtual void Down()
Definition: spinfld.cxx:362
virtual void Modify() override
Definition: field.cxx:1511
sal_Int64 GetMin() const
Definition: field.hxx:101
MetricBox(vcl::Window *pParent, WinBits nWinStyle)
Definition: field.cxx:1557
static bool ImplCurrencyGetValue(const OUString &rStr, sal_Int64 &rValue, sal_uInt16 nDecDigits, const LocaleDataWrapper &rWrapper)
Definition: field.cxx:1653
const LanguageTag & GetLanguageTag() const
bool mbStrictFormat
Definition: field.hxx:51
const LanguageTag & GetLanguageTag() const
Definition: field.cxx:504
FieldUnit meUnit
Definition: field.hxx:194
virtual Size CalcMinimumSize() const override
Definition: field.cxx:1413
SAL_DLLPRIVATE void ImplMetricReformat(const OUString &rStr, double &rValue, OUString &rOutStr)
Definition: field.cxx:1218
virtual void ReformatAll()
Definition: field.cxx:481
const OUString & getNumDecimalSep() const
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: combobox.cxx:693
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:483
bool IsDropDownBox() const
Definition: combobox.cxx:605
void Justify()
#define SAL_MAX_INT32
virtual bool PreNotify(NotifyEvent &rNEvt)
Definition: event.cxx:52
int i
constexpr sal_uInt16 KEYGROUP_FKEYS
Definition: keycodes.hxx:39
static bool isAlpha(const sal_Unicode ch)
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: combobox.cxx:715
virtual void Reformat()
Definition: field.cxx:477
bool mbReformat
Definition: field.hxx:50
static bool isControl(const sal_Unicode ch)
sal_Int64 GetCorrectedValue(FieldUnit eOutUnit) const
Definition: field.cxx:1393
const css::lang::Locale & GetLocale() const
Definition: field.cxx:496
virtual void First() override
Definition: field.cxx:1529
sal_Int64 Normalize(sal_Int64 nValue) const
Definition: field.cxx:669
void SetEmptyFieldValueData(bool bValue)
Definition: field.hxx:59
void SetUpdateMode(bool bUpdate)
Definition: window.cxx:2967
virtual OUString GetText() const override
Definition: edit.cxx:2562
bool IsUpdateMode() const
Definition: window2.cxx:1167
const AllSettings & GetSettings() const
Definition: window3.cxx:129
virtual void Modify()
Definition: edit.cxx:2312
float u
void RemoveEntryAt(sal_Int32 nPos)
Definition: combobox.cxx:922
void FormatValue(Selection const *pNewSelection=nullptr)
Definition: field.cxx:540
MouseNotifyEvent GetType() const
Definition: event.hxx:308
static OUString ImplMetricGetUnitText(const OUString &rStr)
Definition: field.cxx:931
SAL_DLLPRIVATE bool ImplGetEmptyFieldValue() const
Definition: field.hxx:57
virtual Size CalcMinimumSize() const override
Definition: field.cxx:1570
sal_Int64 Denormalize(sal_Int64 nValue) const
Definition: field.cxx:674
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:1541
void put(const char *pPropName, const OUString &rPropValue)
sal_Int64 mnLast
Definition: field.hxx:141
bool TextToValue(const OUString &rStr, double &rValue, sal_Int64 nBaseValue, sal_uInt16 nDecDigits, const LocaleDataWrapper &rLocaleDataWrapper, FieldUnit eUnit)
Definition: field.cxx:1199
void SetLast(sal_Int64 nNewLast, FieldUnit eInUnit)
Definition: field.cxx:1458
tools::Long Len() const
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: field.cxx:1482
SAL_DLLPRIVATE void ImplSetText(const OUString &rText, Selection const *pNewSel=nullptr)
Definition: field.cxx:512
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: field.cxx:1471
virtual void Reformat() override
Definition: field.cxx:696
void FieldDown()
Definition: field.cxx:721
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:1315
virtual void SetUnit(FieldUnit meUnit) override
Definition: field.cxx:1429
void SetUseThousandSep(bool b)
Definition: field.cxx:589
void MarkToBeReformatted(bool b)
Definition: field.hxx:75
sal_Int64 mnMax
Definition: field.hxx:134
void SetCustomUnitText(const OUString &rStr)
Definition: field.cxx:1254
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:57
virtual void First()
Definition: spinfld.cxx:367
virtual sal_Int64 GetValueFromString(const OUString &rStr) const
Definition: field.cxx:626
static OUString formatPercent(double dNumber, const LanguageTag &rLangTag)
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: spinfld.cxx:809
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: field.cxx:1495
virtual void Down() override
Definition: field.cxx:1523
sal_Int64 GetMax() const
Definition: field.hxx:103
WindowType
sal_Int32 GetEntryCount() const
Definition: combobox.cxx:962
constexpr tools::Long Height() const
MetricFormatter(Edit *pEdit)
Definition: field.cxx:1232
void SetValueFromString(const OUString &rStr)
Definition: field.cxx:646
void FieldFirst()
Definition: field.cxx:735
tools::Long Min() const
sal_Int64 GetLast() const
Definition: field.hxx:110
OUString GetValueString() const
Definition: field.cxx:639
MetricField(vcl::Window *pParent, WinBits nWinStyle)
Definition: field.cxx:1400
sal_Unicode GetCharCode() const
Definition: event.hxx:56
virtual void ReformatAll() override
Definition: field.cxx:1630
virtual void Up() override
Definition: field.cxx:1517
FormatterBase(Edit *pField)
Definition: field.cxx:441
virtual OUString CreateFieldText(sal_Int64 nValue) const override
Definition: field.cxx:1265
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: field.cxx:1407
sal_Int64 mnSpinSize
Definition: field.hxx:139
sal_Int64 mnFirst
Definition: field.hxx:140
virtual void Last()
Definition: spinfld.cxx:372
void SetDecimalDigits(sal_uInt16 nDigits)
Definition: field.cxx:595
void SetValue(sal_Int64 nNewValue, FieldUnit eInUnit)
Definition: field.cxx:1260
SAL_DLLPRIVATE void ImplNumericReformat()
Definition: field.cxx:547
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:831
void * GetEntryData(sal_Int32 nPos) const
Definition: combobox.cxx:1318
void SetUserValue(sal_Int64 nNewValue, FieldUnit eInUnit)
Definition: field.cxx:1308
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:1028
A widget used to choose from a list of items and which has an entry.
Definition: combobox.hxx:38
void FieldUp()
Definition: field.cxx:707
#define SELECTION_MAX
bool IsUseThousandSep() const
Definition: field.hxx:118
virtual ~NumericFormatter() override
Definition: field.cxx:571
MapUnit
double ConvertDoubleValue(double nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, FieldUnit eInUnit, FieldUnit eOutUnit)
Definition: field.cxx:1113
#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:133
virtual ~MetricFormatter() override
Definition: field.cxx:1238
sal_Int32 InsertEntry(const OUString &rStr, sal_Int32 nPos=COMBOBOX_APPEND)
Definition: combobox.cxx:881
const FieldUnitStringList & ImplGetFieldUnits()
Definition: svdata.cxx:263
virtual void SetText(const OUString &rStr) override
Definition: edit.cxx:2543
NumericFormatter(Edit *pEdit)
Definition: field.cxx:553
sal_Int64 ClipAgainstMinMax(sal_Int64 nValue) const
Definition: field.cxx:778
virtual ~FormatterBase()
Definition: field.cxx:451
const LocaleDataWrapper & GetLocaleDataWrapper() const
Definition: field.cxx:472
void SetUserValue(sal_Int64 nNewValue)
Definition: field.cxx:621
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: field.cxx:1608
aStr
Size CalcMinimumSize() const override
Definition: combobox.cxx:1022
static bool ImplCurrencyProcessKeyInput(const KeyEvent &rKEvt, bool bUseThousandSep, const LocaleDataWrapper &rWrapper)
Definition: field.cxx:1646
#define SAL_MAX_INT64
sal_uInt16 mnDecimalDigits
Definition: field.hxx:158
virtual void SetValue(sal_Int64 nNewValue)
Definition: field.cxx:601
sal_Int16 nValue
VclPtr< Edit > mpField
Definition: field.hxx:47
virtual void Modify() override
Definition: combobox.cxx:820
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: field.cxx:1564
bool IsMod2() const
Definition: keycod.hxx:58
virtual void SetValue(tools::Long nNew) override
static double nonValueDoubleToValueDouble(double nValue)
Definition: field.cxx:1021