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