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