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