LibreOffice Module vcl (master)  1
fmtfield.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 <tools/debug.hxx>
21 #include <boost/property_tree/json_parser.hpp>
23 #include <comphelper/string.hxx>
25 #include <vcl/builder.hxx>
26 #include <vcl/event.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/commandevent.hxx>
29 #include <svl/zformat.hxx>
30 #include <vcl/toolkit/fmtfield.hxx>
31 #include <vcl/uitest/uiobject.hxx>
33 #include <vcl/weld.hxx>
35 #include <unotools/syslocale.hxx>
36 #include <limits>
37 #include <map>
38 #include <rtl/math.hxx>
39 #include <rtl/ustrbuf.hxx>
40 #include <sal/log.hxx>
41 #include <svl/numformat.hxx>
42 #include <osl/diagnose.h>
43 #include <tools/json_writer.hxx>
44 
45 using namespace ::com::sun::star::lang;
46 using namespace ::com::sun::star::util;
47 
48 // hmm. No support for regular expression. Well, I always (not really :) wanted to write a finite automat
49 // so here comes a finite automat ...
50 
51 namespace validation
52 {
54  {
55  _rRow.insert( Transition( '_', END ) );
56  }
57 
59  {
60  _rRow.insert( Transition( 'e', EXPONENT_START ) );
61  }
62 
63  static void lcl_insertSignTransitions( StateTransitions& _rRow, const State eNextState )
64  {
65  _rRow.insert( Transition( '-', eNextState ) );
66  _rRow.insert( Transition( '+', eNextState ) );
67  }
68 
69  static void lcl_insertDigitTransitions( StateTransitions& _rRow, const State eNextState )
70  {
71  for ( sal_Unicode aChar = '0'; aChar <= '9'; ++aChar )
72  _rRow.insert( Transition( aChar, eNextState ) );
73  }
74 
75  static void lcl_insertCommonPreCommaTransitions( StateTransitions& _rRow, const sal_Unicode _cThSep, const sal_Unicode _cDecSep )
76  {
77  // digits are allowed
79 
80  // the thousand separator is allowed
81  _rRow.insert( Transition( _cThSep, DIGIT_PRE_COMMA ) );
82 
83  // a comma is allowed
84  _rRow.insert( Transition( _cDecSep, DIGIT_POST_COMMA ) );
85  }
86 
87  NumberValidator::NumberValidator( const sal_Unicode _cThSep, const sal_Unicode _cDecSep )
88  {
89  // build up our transition table
90 
91  // how to proceed from START
92  {
94  rRow.insert( Transition( '_', NUM_START ) );
95  // if we encounter the normalizing character, we want to proceed with the number
96  }
97 
98  // how to proceed from NUM_START
99  {
101 
102  // a sign is allowed
104 
105  // common transitions for the two pre-comma states
106  lcl_insertCommonPreCommaTransitions( rRow, _cThSep, _cDecSep );
107 
108  // the exponent may start here
109  // (this would mean string like "_+e10_", but this is a valid fragment, though no valid number)
111  }
112 
113  // how to proceed from DIGIT_PRE_COMMA
114  {
116 
117  // common transitions for the two pre-comma states
118  lcl_insertCommonPreCommaTransitions( rRow, _cThSep, _cDecSep );
119 
120  // the exponent may start here
122 
123  // the final transition indicating the end of the string
124  // (if there is no comma and no post-comma, then the string may end here)
125  lcl_insertStopTransition( rRow );
126  }
127 
128  // how to proceed from DIGIT_POST_COMMA
129  {
131 
132  // there might be digits, which would keep the state at DIGIT_POST_COMMA
134 
135  // the exponent may start here
137 
138  // the string may end here
139  lcl_insertStopTransition( rRow );
140  }
141 
142  // how to proceed from EXPONENT_START
143  {
145 
146  // there may be a sign
148 
149  // there may be digits
151 
152  // the string may end here
153  lcl_insertStopTransition( rRow );
154  }
155 
156  // how to proceed from EXPONENT_DIGIT
157  {
159 
160  // there may be digits
162 
163  // the string may end here
164  lcl_insertStopTransition( rRow );
165  }
166 
167  // how to proceed from END
168  {
169  /*StateTransitions& rRow =*/ m_aTransitions[ EXPONENT_DIGIT ];
170  // no valid transition to leave this state
171  // (note that we, for consistency, nevertheless want to have a row in the table)
172  }
173  }
174 
175  bool NumberValidator::implValidateNormalized( const OUString& _rText )
176  {
177  const sal_Unicode* pCheckPos = _rText.getStr();
178  State eCurrentState = START;
179 
180  while ( END != eCurrentState )
181  {
182  // look up the transition row for the current state
183  TransitionTable::const_iterator aRow = m_aTransitions.find( eCurrentState );
184  DBG_ASSERT( m_aTransitions.end() != aRow,
185  "NumberValidator::implValidateNormalized: invalid transition table (row not found)!" );
186 
187  if ( m_aTransitions.end() != aRow )
188  {
189  // look up the current character in this row
190  StateTransitions::const_iterator aTransition = aRow->second.find( *pCheckPos );
191  if ( aRow->second.end() != aTransition )
192  {
193  // there is a valid transition for this character
194  eCurrentState = aTransition->second;
195  ++pCheckPos;
196  continue;
197  }
198  }
199 
200  // if we're here, there is no valid transition
201  break;
202  }
203 
204  DBG_ASSERT( ( END != eCurrentState ) || ( 0 == *pCheckPos ),
205  "NumberValidator::implValidateNormalized: inconsistency!" );
206  // if we're at END, then the string should be done, too - the string should be normalized, means ending
207  // a "_" and not containing any other "_" (except at the start), and "_" is the only possibility
208  // to reach the END state
209 
210  // the string is valid if and only if we reached the final state
211  return ( END == eCurrentState );
212  }
213 
214  bool NumberValidator::isValidNumericFragment( std::u16string_view _rText )
215  {
216  if ( _rText.empty() )
217  // empty strings are always allowed
218  return true;
219 
220  // normalize the string
221  OUString sNormalized = OUString::Concat("_") + _rText + "_";
222 
223  return implValidateNormalized( sNormalized );
224  }
225 }
226 
229 
230 SvNumberFormatter* Formatter::StaticFormatter::GetFormatter()
231 {
232  if (!s_cFormatter)
233  {
234  // get the Office's locale and translate
235  LanguageType eSysLanguage = SvtSysLocale().GetLanguageTag().getLanguageType( false);
238  eSysLanguage);
239  }
240  return s_cFormatter;
241 }
242 
244 {
245  ++s_nReferences;
246 }
247 
249 {
250  if (--s_nReferences == 0)
251  {
252  delete s_cFormatter;
253  s_cFormatter = nullptr;
254  }
255 }
256 
258  :m_aLastSelection(0,0)
259  ,m_dMinValue(0)
260  ,m_dMaxValue(0)
261  ,m_bHasMin(false)
262  ,m_bHasMax(false)
263  ,m_bWrapOnLimits(false)
264  ,m_bStrictFormat(true)
265  ,m_bEnableEmptyField(true)
266  ,m_bAutoColor(false)
267  ,m_bEnableNaN(false)
270  ,m_dCurrentValue(0)
271  ,m_dDefaultValue(0)
272  ,m_nFormatKey(0)
273  ,m_pFormatter(nullptr)
274  ,m_dSpinSize(1)
275  ,m_dSpinFirst(-1000000)
276  ,m_dSpinLast(1000000)
277  ,m_bTreatAsNumber(true)
278  ,m_pLastOutputColor(nullptr)
280 {
281 }
282 
284 {
285 }
286 
287 void Formatter::SetFieldText(const OUString& rStr, const Selection& rNewSelection)
288 {
289  SetEntryText(rStr, rNewSelection);
291 }
292 
293 void Formatter::SetTextFormatted(const OUString& rStr)
294 {
295  SAL_INFO_IF(GetOrCreateFormatter()->IsTextFormat(m_nFormatKey), "svtools",
296  "FormattedField::SetTextFormatted : valid only with text formats !");
297 
298  m_sCurrentTextValue = rStr;
299 
300  OUString sFormatted;
301  double dNumber = 0.0;
302  // IsNumberFormat changes the format key parameter
303  sal_uInt32 nTempFormatKey = static_cast< sal_uInt32 >( m_nFormatKey );
305  GetOrCreateFormatter()->IsNumberFormat(m_sCurrentTextValue, nTempFormatKey, dNumber) )
306  {
307  GetOrCreateFormatter()->GetInputLineString(dNumber, m_nFormatKey, sFormatted);
308  }
309  else
310  {
312  m_nFormatKey,
313  sFormatted,
315  }
316 
317  // calculate the new selection
319  Selection aNewSel(aSel);
320  aNewSel.Justify();
321  sal_Int32 nNewLen = sFormatted.getLength();
322  sal_Int32 nCurrentLen = GetEntryText().getLength();
323  if ((nNewLen > nCurrentLen) && (aNewSel.Max() == nCurrentLen))
324  { // the new text is longer and the cursor was behind the last char (of the old text)
325  if (aNewSel.Min() == 0)
326  { // the whole text was selected -> select the new text on the whole, too
327  aNewSel.Max() = nNewLen;
328  if (!nCurrentLen)
329  { // there wasn't really a previous selection (as there was no previous text), we're setting a new one -> check the selection options
331  if (nSelOptions & SelectionOptions::ShowFirst)
332  { // selection should be from right to left -> swap min and max
333  aNewSel.Min() = aNewSel.Max();
334  aNewSel.Max() = 0;
335  }
336  }
337  }
338  else if (aNewSel.Max() == aNewSel.Min())
339  { // there was no selection -> set the cursor behind the new last char
340  aNewSel.Max() = nNewLen;
341  aNewSel.Min() = nNewLen;
342  }
343  }
344  else if (aNewSel.Max() > nNewLen)
345  aNewSel.Max() = nNewLen;
346  else
347  aNewSel = aSel; // don't use the justified version
348  SetEntryText(sFormatted, aNewSel);
350 }
351 
352 OUString const & Formatter::GetTextValue() const
353 {
354  if (m_ValueState != valueString )
355  {
356  const_cast<Formatter*>(this)->m_sCurrentTextValue = GetEntryText();
357  const_cast<Formatter*>(this)->m_ValueState = valueString;
358  }
359  return m_sCurrentTextValue;
360 }
361 
362 void Formatter::EnableNotANumber(bool _bEnable)
363 {
364  if ( m_bEnableNaN == _bEnable )
365  return;
366 
367  m_bEnableNaN = _bEnable;
368 }
369 
370 void Formatter::SetAutoColor(bool _bAutomatic)
371 {
372  if (_bAutomatic == m_bAutoColor)
373  return;
374 
375  m_bAutoColor = _bAutomatic;
376  if (m_bAutoColor)
377  {
378  // if auto color is switched on, adjust the current text color, too
380  }
381 }
382 
383 void Formatter::Modify(bool makeValueDirty)
384 {
385  if (!IsStrictFormat())
386  {
387  if(makeValueDirty)
389  FieldModified();
390  return;
391  }
392 
393  OUString sCheck = GetEntryText();
394  if (CheckText(sCheck))
395  {
396  m_sLastValidText = sCheck;
398  if(makeValueDirty)
400  }
401  else
402  {
404  }
405 
406  FieldModified();
407 }
408 
409 void Formatter::ImplSetTextImpl(const OUString& rNew, Selection const * pNewSel)
410 {
411  if (m_bAutoColor)
413 
414  if (pNewSel)
415  SetEntryText(rNew, *pNewSel);
416  else
417  {
419  aSel.Justify();
420 
421  sal_Int32 nNewLen = rNew.getLength();
422  sal_Int32 nCurrentLen = GetEntryText().getLength();
423 
424  if ((nNewLen > nCurrentLen) && (aSel.Max() == nCurrentLen))
425  { // new text is longer and the cursor is behind the last char
426  if (aSel.Min() == 0)
427  {
428  if (!nCurrentLen)
429  { // there wasn't really a previous selection (as there was no previous text)
430  aSel.Max() = 0;
431  }
432  else
433  { // the whole text was selected -> select the new text on the whole, too
434  aSel.Max() = nNewLen;
435  }
436  }
437  else if (aSel.Max() == aSel.Min())
438  { // there was no selection -> set the cursor behind the new last char
439  aSel.Max() = nNewLen;
440  aSel.Min() = nNewLen;
441  }
442  }
443  else if (aSel.Max() > nNewLen)
444  aSel.Max() = nNewLen;
445  SetEntryText(rNew, aSel);
446  }
447 
448  m_ValueState = valueDirty; // not always necessary, but better re-evaluate for safety reasons
449 }
450 
452 {
453  m_nFormatKey = nFormatKey;
454  bool bNeedFormatter = (m_pFormatter == nullptr) && (nFormatKey != 0);
455  if (bNeedFormatter)
456  {
457  GetOrCreateFormatter(); // this creates a standard formatter
458 
459  // It might happen that the standard formatter makes no sense here, but it takes a default
460  // format. Thus, it is possible to set one of the other standard keys (which are spanning
461  // across multiple formatters).
462  m_nFormatKey = nFormatKey;
463  // When calling SetFormatKey without a formatter, the key must be one of the standard values
464  // that is available for all formatters (and, thus, also in this new one).
465  DBG_ASSERT(m_pFormatter->GetEntry(nFormatKey) != nullptr, "FormattedField::ImplSetFormatKey : invalid format key !");
466  }
467 }
468 
470 {
471  bool bNoFormatter = (m_pFormatter == nullptr);
472  ImplSetFormatKey(nFormatKey);
474 }
475 
476 void Formatter::SetFormatter(SvNumberFormatter* pFormatter, bool bResetFormat)
477 {
478 
479  if (bResetFormat)
480  {
481  m_pFormatter = pFormatter;
482 
483  // calc the default format key from the Office's UI locale
484  if ( m_pFormatter )
485  {
486  // get the Office's locale and translate
487  LanguageType eSysLanguage = SvtSysLocale().GetLanguageTag().getLanguageType( false);
488  // get the standard numeric format for this language
489  m_nFormatKey = m_pFormatter->GetStandardFormat( SvNumFormatType::NUMBER, eSysLanguage );
490  }
491  else
492  m_nFormatKey = 0;
493  }
494  else
495  {
496  LanguageType aOldLang;
497  OUString sOldFormat = GetFormat(aOldLang);
498 
499  sal_uInt32 nDestKey = pFormatter->TestNewString(sOldFormat);
500  if (nDestKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
501  {
502  // language of the new formatter
503  const SvNumberformat* pDefaultEntry = pFormatter->GetEntry(0);
504  LanguageType aNewLang = pDefaultEntry ? pDefaultEntry->GetLanguage() : LANGUAGE_DONTKNOW;
505 
506  // convert the old format string into the new language
507  sal_Int32 nCheckPos;
509  pFormatter->PutandConvertEntry(sOldFormat, nCheckPos, nType, nDestKey, aOldLang, aNewLang, true);
510  m_nFormatKey = nDestKey;
511  }
512  m_pFormatter = pFormatter;
513  }
514 
516 }
517 
518 OUString Formatter::GetFormat(LanguageType& eLang) const
519 {
520  const SvNumberformat* pFormatEntry = GetOrCreateFormatter()->GetEntry(m_nFormatKey);
521  DBG_ASSERT(pFormatEntry != nullptr, "FormattedField::GetFormat: no number format for the given format key.");
522  OUString sFormatString = pFormatEntry ? pFormatEntry->GetFormatstring() : OUString();
523  eLang = pFormatEntry ? pFormatEntry->GetLanguage() : LANGUAGE_DONTKNOW;
524 
525  return sFormatString;
526 }
527 
528 bool Formatter::SetFormat(const OUString& rFormatString, LanguageType eLang)
529 {
530  sal_uInt32 nNewKey = GetOrCreateFormatter()->TestNewString(rFormatString, eLang);
531  if (nNewKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
532  {
533  sal_Int32 nCheckPos;
535  OUString rFormat(rFormatString);
536  if (!GetOrCreateFormatter()->PutEntry(rFormat, nCheckPos, nType, nNewKey, eLang))
537  return false;
538  DBG_ASSERT(nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND, "FormattedField::SetFormatString : PutEntry returned an invalid key !");
539  }
540 
541  if (nNewKey != m_nFormatKey)
542  SetFormatKey(nNewKey);
543  return true;
544 }
545 
547 {
548  DBG_ASSERT(!GetOrCreateFormatter()->IsTextFormat(m_nFormatKey),
549  "FormattedField::GetThousandsSep : Are you sure what you are doing when setting the precision of a text format?");
550 
551  bool bThousand, IsRed;
552  sal_uInt16 nPrecision, nLeadingCnt;
553  GetOrCreateFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nLeadingCnt);
554 
555  return bThousand;
556 }
557 
558 void Formatter::SetThousandsSep(bool _bUseSeparator)
559 {
560  DBG_ASSERT(!GetOrCreateFormatter()->IsTextFormat(m_nFormatKey),
561  "FormattedField::SetThousandsSep : Are you sure what you are doing when setting the precision of a text format?");
562 
563  // get the current settings
564  bool bThousand, IsRed;
565  sal_uInt16 nPrecision, nLeadingCnt;
566  GetOrCreateFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nLeadingCnt);
567  if (bThousand == _bUseSeparator)
568  return;
569 
570  // we need the language for the following
571  LanguageType eLang;
572  GetFormat(eLang);
573 
574  // generate a new format ...
575  OUString sFmtDescription = GetOrCreateFormatter()->GenerateFormat(m_nFormatKey, eLang, _bUseSeparator, IsRed, nPrecision, nLeadingCnt);
576  // ... and introduce it to the formatter
577  sal_Int32 nCheckPos = 0;
578  sal_uInt32 nNewKey;
580  GetOrCreateFormatter()->PutEntry(sFmtDescription, nCheckPos, nType, nNewKey, eLang);
581 
582  // set the new key
583  ImplSetFormatKey(nNewKey);
585 }
586 
587 sal_uInt16 Formatter::GetDecimalDigits() const
588 {
589  DBG_ASSERT(!GetOrCreateFormatter()->IsTextFormat(m_nFormatKey),
590  "FormattedField::GetDecimalDigits : Are you sure what you are doing when setting the precision of a text format?");
591 
592  bool bThousand, IsRed;
593  sal_uInt16 nPrecision, nLeadingCnt;
594  GetOrCreateFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nLeadingCnt);
595 
596  return nPrecision;
597 }
598 
599 void Formatter::SetDecimalDigits(sal_uInt16 _nPrecision)
600 {
601  DBG_ASSERT(!GetOrCreateFormatter()->IsTextFormat(m_nFormatKey),
602  "FormattedField::SetDecimalDigits : Are you sure what you are doing when setting the precision of a text format?");
603 
604  // get the current settings
605  bool bThousand, IsRed;
606  sal_uInt16 nPrecision, nLeadingCnt;
607  GetOrCreateFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nLeadingCnt);
608  if (nPrecision == _nPrecision)
609  return;
610 
611  // we need the language for the following
612  LanguageType eLang;
613  GetFormat(eLang);
614 
615  // generate a new format ...
616  OUString sFmtDescription = GetOrCreateFormatter()->GenerateFormat(m_nFormatKey, eLang, bThousand, IsRed, _nPrecision, nLeadingCnt);
617  // ... and introduce it to the formatter
618  sal_Int32 nCheckPos = 0;
619  sal_uInt32 nNewKey;
621  GetOrCreateFormatter()->PutEntry(sFmtDescription, nCheckPos, nType, nNewKey, eLang);
622 
623  // set the new key
624  ImplSetFormatKey(nNewKey);
626 }
627 
629 {
630  m_pLastOutputColor = nullptr;
631 
632  if ( (_nWhat == FORMAT_CHANGE_TYPE::FORMATTER) && m_pFormatter )
634 
635  ReFormat();
636 }
637 
639 {
640  // special treatment for empty texts
641  if (GetEntryText().isEmpty())
642  {
643  if (!IsEmptyFieldEnabled())
644  {
645  if (TreatingAsNumber())
646  {
648  Modify();
650  }
651  else
652  {
653  OUString sNew = GetTextValue();
654  if (!sNew.isEmpty())
655  SetTextFormatted(sNew);
656  else
659  }
660  }
661  }
662  else
663  {
664  Commit();
665  }
666 }
667 
669 {
670  // remember the old text
671  OUString sOld(GetEntryText());
672 
673  // do the reformat
674  ReFormat();
675 
676  // did the text change?
677  if (GetEntryText() != sOld)
678  { // consider the field as modified,
679  // but we already have the most recent value;
680  // don't reparse it from the text
681  // (can lead to data loss when the format is lossy,
682  // as is e.g. our default date format: 2-digit year!)
683  Modify(false);
684  }
685 }
686 
688 {
689  if (!IsEmptyFieldEnabled() || !GetEntryText().isEmpty())
690  {
691  if (TreatingAsNumber())
692  {
693  double dValue = GetValue();
694  if ( m_bEnableNaN && std::isnan( dValue ) )
695  return;
696  ImplSetValue( dValue, true );
697  }
698  else
700  }
701 }
702 
703 void Formatter::SetMinValue(double dMin)
704 {
705  DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMinValue : only to be used in numeric mode !");
706 
707  m_dMinValue = dMin;
708  m_bHasMin = true;
709  // for checking the current value at the new border -> ImplSetValue
710  ReFormat();
711 }
712 
713 void Formatter::SetMaxValue(double dMax)
714 {
715  DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMaxValue : only to be used in numeric mode !");
716 
717  m_dMaxValue = dMax;
718  m_bHasMax = true;
719  // for checking the current value at the new border -> ImplSetValue
720  ReFormat();
721 }
722 
723 void Formatter::SetTextValue(const OUString& rText)
724 {
725  SetFieldText(rText, Selection(0, 0));
726  ReFormat();
727 }
728 
729 void Formatter::EnableEmptyField(bool bEnable)
730 {
731  if (bEnable == m_bEnableEmptyField)
732  return;
733 
734  m_bEnableEmptyField = bEnable;
735  if (!m_bEnableEmptyField && GetEntryText().isEmpty())
737 }
738 
739 void Formatter::ImplSetValue(double dVal, bool bForce)
740 {
741  if (m_bHasMin && (dVal<m_dMinValue))
742  {
743  dVal = m_bWrapOnLimits ? fmod(dVal + m_dMaxValue + 1 - m_dMinValue, m_dMaxValue + 1) + m_dMinValue
744  : m_dMinValue;
745  }
746  if (m_bHasMax && (dVal>m_dMaxValue))
747  {
748  dVal = m_bWrapOnLimits ? fmod(dVal - m_dMinValue, m_dMaxValue + 1) + m_dMinValue
749  : m_dMaxValue;
750  }
751  if (!bForce && (dVal == GetValue()))
752  return;
753 
754  DBG_ASSERT(GetOrCreateFormatter() != nullptr, "FormattedField::ImplSetValue : can't set a value without a formatter !");
755 
757  UpdateCurrentValue(dVal);
758 
759  if (!m_aOutputHdl.IsSet() || !m_aOutputHdl.Call(nullptr))
760  {
761  OUString sNewText;
763  {
764  // first convert the number as string in standard format
765  OUString sTemp;
767  // then encode the string in the corresponding text format
769  }
770  else
771  {
773  {
775  }
776  else
777  {
779  }
780  }
781  ImplSetTextImpl(sNewText, nullptr);
782  DBG_ASSERT(CheckText(sNewText), "FormattedField::ImplSetValue : formatted string doesn't match the criteria !");
783  }
784 
786 }
787 
788 bool Formatter::ImplGetValue(double& dNewVal)
789 {
790  dNewVal = m_dCurrentValue;
791  if (m_ValueState == valueDouble)
792  return true;
793 
794  dNewVal = m_dDefaultValue;
795  OUString sText(GetEntryText());
796  if (sText.isEmpty())
797  return true;
798 
799  bool bUseExternalFormatterValue = false;
800  if (m_aInputHdl.IsSet())
801  {
802  sal_Int64 nResult;
803  auto eState = m_aInputHdl.Call(&nResult);
804  bUseExternalFormatterValue = eState != TRISTATE_INDET;
805  if (bUseExternalFormatterValue)
806  {
807  if (eState == TRISTATE_TRUE)
808  {
809  dNewVal = nResult;
811  }
812  else
813  dNewVal = m_dCurrentValue;
814  }
815  }
816 
817  if (!bUseExternalFormatterValue)
818  {
819  DBG_ASSERT(GetOrCreateFormatter() != nullptr, "FormattedField::ImplGetValue : can't give you a current value without a formatter !");
820 
821  sal_uInt32 nFormatKey = m_nFormatKey; // IsNumberFormat changes the FormatKey!
822 
823  if (GetOrCreateFormatter()->IsTextFormat(nFormatKey) && m_bTreatAsNumber)
824  // for detection of values like "1,1" in fields that are formatted as text
825  nFormatKey = 0;
826 
827  // special treatment for percentage formatting
828  if (GetOrCreateFormatter()->GetType(m_nFormatKey) == SvNumFormatType::PERCENT)
829  {
830  // the language of our format
832  // the default number format for this language
833  sal_uLong nStandardNumericFormat = m_pFormatter->GetStandardFormat(SvNumFormatType::NUMBER, eLanguage);
834 
835  sal_uInt32 nTempFormat = nStandardNumericFormat;
836  double dTemp;
837  if (m_pFormatter->IsNumberFormat(sText, nTempFormat, dTemp) &&
838  SvNumFormatType::NUMBER == m_pFormatter->GetType(nTempFormat))
839  // the string is equivalent to a number formatted one (has no % sign) -> append it
840  sText += "%";
841  // (with this, an input of '3' becomes '3%', which then by the formatter is translated
842  // into 0.03. Without this, the formatter would give us the double 3 for an input '3',
843  // which equals 300 percent.
844  }
845  if (!GetOrCreateFormatter()->IsNumberFormat(sText, nFormatKey, dNewVal))
846  return false;
847  }
848 
849  if (m_bHasMin && (dNewVal<m_dMinValue))
850  dNewVal = m_dMinValue;
851  if (m_bHasMax && (dNewVal>m_dMaxValue))
852  dNewVal = m_dMaxValue;
853  return true;
854 }
855 
856 void Formatter::SetValue(double dVal)
857 {
859 }
860 
862 {
863  if ( !ImplGetValue( m_dCurrentValue ) )
864  UpdateCurrentValue(m_bEnableNaN ? std::numeric_limits<double>::quiet_NaN() : m_dDefaultValue);
865 
867  return m_dCurrentValue;
868 }
869 
871 {
873 }
874 
876 {
878 }
879 
880 namespace
881 {
882  class FieldFormatter : public Formatter
883  {
884  private:
885  FormattedField& m_rSpinButton;
886  public:
887  FieldFormatter(FormattedField& rSpinButton)
888  : m_rSpinButton(rSpinButton)
889  {
890  }
891 
892  // Formatter overrides
893  virtual Selection GetEntrySelection() const override
894  {
895  return m_rSpinButton.GetSelection();
896  }
897 
898  virtual OUString GetEntryText() const override
899  {
900  return m_rSpinButton.GetText();
901  }
902 
903  void SetEntryText(const OUString& rText, const Selection& rSel) override
904  {
905  m_rSpinButton.SpinField::SetText(rText, rSel);
906  }
907 
908  virtual void SetEntryTextColor(const Color* pColor) override
909  {
910  if (pColor)
911  m_rSpinButton.SetControlForeground(*pColor);
912  else
913  m_rSpinButton.SetControlForeground();
914  }
915 
916  virtual SelectionOptions GetEntrySelectionOptions() const override
917  {
918  return m_rSpinButton.GetSettings().GetStyleSettings().GetSelectionOptions();
919  }
920 
921  virtual void FieldModified() override
922  {
923  m_rSpinButton.SpinField::Modify();
924  }
925  };
926 
927  class DoubleNumericFormatter : public FieldFormatter
928  {
929  private:
930  DoubleNumericField& m_rNumericSpinButton;
931  public:
932  DoubleNumericFormatter(DoubleNumericField& rNumericSpinButton)
933  : FieldFormatter(rNumericSpinButton)
934  , m_rNumericSpinButton(rNumericSpinButton)
935  {
936  }
937 
938  virtual bool CheckText(const OUString& sText) const override
939  {
940  // We'd like to implement this using the NumberFormatter::IsNumberFormat, but unfortunately, this doesn't
941  // recognize fragments of numbers (like, for instance "1e", which happens during entering e.g. "1e10")
942  // Thus, the roundabout way via a regular expression
943  return m_rNumericSpinButton.GetNumberValidator().isValidNumericFragment(sText);
944  }
945 
946  virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat) override
947  {
948  m_rNumericSpinButton.ResetConformanceTester();
949  FieldFormatter::FormatChanged(nWhat);
950  }
951  };
952 
953  class DoubleCurrencyFormatter : public FieldFormatter
954  {
955  private:
956  DoubleCurrencyField& m_rCurrencySpinButton;
957  bool m_bChangingFormat;
958  public:
959  DoubleCurrencyFormatter(DoubleCurrencyField& rNumericSpinButton)
960  : FieldFormatter(rNumericSpinButton)
961  , m_rCurrencySpinButton(rNumericSpinButton)
962  , m_bChangingFormat(false)
963  {
964  }
965 
966  virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat) override
967  {
968  if (m_bChangingFormat)
969  {
970  FieldFormatter::FormatChanged(nWhat);
971  return;
972  }
973 
974  switch (nWhat)
975  {
979  // the aspects which changed don't take our currency settings into account (in fact, they most probably
980  // destroyed them)
981  m_rCurrencySpinButton.UpdateCurrencyFormat();
982  break;
984  OSL_FAIL("DoubleCurrencyField::FormatChanged : somebody modified my key !");
985  // We always build our own format from the settings we get via special methods (setCurrencySymbol etc.).
986  // Nobody but ourself should modify the format key directly!
987  break;
988  default: break;
989  }
990 
991  FieldFormatter::FormatChanged(nWhat);
992  }
993 
994  void GuardSetFormat(const OUString& rString, LanguageType eLanguage)
995  {
996  // set this new basic format
997  m_bChangingFormat = true;
998  SetFormat(rString, eLanguage);
999  m_bChangingFormat = false;
1000  }
1001 
1002  };
1003 }
1004 
1005 DoubleNumericField::DoubleNumericField(vcl::Window* pParent, WinBits nStyle)
1006  : FormattedField(pParent, nStyle)
1007 {
1008  m_xOwnFormatter.reset(new DoubleNumericFormatter(*this));
1009  m_pFormatter = m_xOwnFormatter.get();
1010  ResetConformanceTester();
1011 }
1012 
1013 DoubleNumericField::~DoubleNumericField() = default;
1014 
1015 void DoubleNumericField::ResetConformanceTester()
1016 {
1017  // the thousands and the decimal separator are language dependent
1018  Formatter& rFormatter = GetFormatter();
1019  const SvNumberformat* pFormatEntry = rFormatter.GetOrCreateFormatter()->GetEntry(rFormatter.GetFormatKey());
1020 
1021  sal_Unicode cSeparatorThousand = ',';
1022  sal_Unicode cSeparatorDecimal = '.';
1023  if (pFormatEntry)
1024  {
1025  LocaleDataWrapper aLocaleInfo( LanguageTag( pFormatEntry->GetLanguage()) );
1026 
1027  OUString sSeparator = aLocaleInfo.getNumThousandSep();
1028  if (!sSeparator.isEmpty())
1029  cSeparatorThousand = sSeparator[0];
1030 
1031  sSeparator = aLocaleInfo.getNumDecimalSep();
1032  if (!sSeparator.isEmpty())
1033  cSeparatorDecimal = sSeparator[0];
1034  }
1035 
1036  m_pNumberValidator.reset(new validation::NumberValidator( cSeparatorThousand, cSeparatorDecimal ));
1037 }
1038 
1039 
1040 DoubleCurrencyField::DoubleCurrencyField(vcl::Window* pParent, WinBits nStyle)
1041  :FormattedField(pParent, nStyle)
1042 {
1043  m_xOwnFormatter.reset(new DoubleCurrencyFormatter(*this));
1044  m_pFormatter = m_xOwnFormatter.get();
1045 
1046  m_bPrependCurrSym = false;
1047 
1048  // initialize with a system currency format
1049  m_sCurrencySymbol = SvtSysLocale().GetLocaleData().getCurrSymbol();
1050  UpdateCurrencyFormat();
1051 }
1052 
1053 void DoubleCurrencyField::setCurrencySymbol(const OUString& rSymbol)
1054 {
1055  if (m_sCurrencySymbol == rSymbol)
1056  return;
1057 
1058  m_sCurrencySymbol = rSymbol;
1059  UpdateCurrencyFormat();
1060  m_pFormatter->FormatChanged(FORMAT_CHANGE_TYPE::CURRENCY_SYMBOL);
1061 }
1062 
1063 void DoubleCurrencyField::setPrependCurrSym(bool _bPrepend)
1064 {
1065  if (m_bPrependCurrSym == _bPrepend)
1066  return;
1067 
1068  m_bPrependCurrSym = _bPrepend;
1069  UpdateCurrencyFormat();
1070  m_pFormatter->FormatChanged(FORMAT_CHANGE_TYPE::CURRSYM_POSITION);
1071 }
1072 
1073 void DoubleCurrencyField::UpdateCurrencyFormat()
1074 {
1075  // the old settings
1076  LanguageType eLanguage;
1077  m_pFormatter->GetFormat(eLanguage);
1078  bool bThSep = m_pFormatter->GetThousandsSep();
1079  sal_uInt16 nDigits = m_pFormatter->GetDecimalDigits();
1080 
1081  // build a new format string with the base class' and my own settings
1082 
1083  /* Strangely with gcc 4.6.3 this needs a temporary LanguageTag, otherwise
1084  * there's
1085  * error: request for member 'getNumThousandSep' in 'aLocaleInfo', which is
1086  * of non-class type 'LocaleDataWrapper(LanguageTag)' */
1087  LanguageTag aLanguageTag( eLanguage);
1088  LocaleDataWrapper aLocaleInfo( aLanguageTag );
1089 
1090  OUStringBuffer sNewFormat;
1091  if (bThSep)
1092  {
1093  sNewFormat.append('#');
1094  sNewFormat.append(aLocaleInfo.getNumThousandSep());
1095  sNewFormat.append("##0");
1096  }
1097  else
1098  sNewFormat.append('0');
1099 
1100  if (nDigits)
1101  {
1102  sNewFormat.append(aLocaleInfo.getNumDecimalSep());
1103 
1104  OUStringBuffer sTemp;
1105  comphelper::string::padToLength(sTemp, nDigits, '0');
1106  sNewFormat.append(sTemp);
1107  }
1108 
1109  if (getPrependCurrSym())
1110  {
1111  OUString sSymbol = getCurrencySymbol();
1112  sSymbol = comphelper::string::strip(sSymbol, ' ');
1113 
1114  OUStringBuffer sTemp("[$");
1115  sTemp.append(sSymbol);
1116  sTemp.append("] ");
1117  sTemp.append(sNewFormat);
1118 
1119  // for negative values : $ -0.00, not -$ 0.00...
1120  // (the real solution would be a possibility to choose a "positive currency format" and a "negative currency format"...
1121  // But not now... (and hey, you could take a formatted field for this...))
1122  // FS - 31.03.00 74642
1123  sTemp.append(";[$");
1124  sTemp.append(sSymbol);
1125  sTemp.append("] -");
1126  sTemp.append(sNewFormat);
1127 
1128  sNewFormat = sTemp;
1129  }
1130  else
1131  {
1132  OUString sTemp = getCurrencySymbol();
1133  sTemp = comphelper::string::strip(sTemp, ' ');
1134 
1135  sNewFormat.append(" [$");
1136  sNewFormat.append(sTemp);
1137  sNewFormat.append(']');
1138  }
1139 
1140  // set this new basic format
1141  static_cast<DoubleCurrencyFormatter*>(m_pFormatter)->GuardSetFormat(sNewFormat.makeStringAndClear(), eLanguage);
1142 }
1143 
1145  : SpinField(pParent, nStyle, WindowType::FORMATTEDFIELD)
1146  , m_pFormatter(nullptr)
1147 {
1148 }
1149 
1151 {
1152  m_pFormatter = nullptr;
1153  m_xOwnFormatter.reset();
1155 }
1156 
1157 void FormattedField::SetText(const OUString& rStr)
1158 {
1159  GetFormatter().SetFieldText(rStr, Selection(0, 0));
1160 }
1161 
1162 void FormattedField::SetText(const OUString& rStr, const Selection& rNewSelection)
1163 {
1164  GetFormatter().SetFieldText(rStr, rNewSelection);
1165  SetSelection(rNewSelection);
1166 }
1167 
1168 bool FormattedField::set_property(const OString &rKey, const OUString &rValue)
1169 {
1170  if (rKey == "digits")
1171  GetFormatter().SetDecimalDigits(rValue.toInt32());
1172  else if (rKey == "wrap")
1173  GetFormatter().SetWrapOnLimits(toBool(rValue));
1174  else
1175  return SpinField::set_property(rKey, rValue);
1176  return true;
1177 }
1178 
1180 {
1181  Formatter& rFormatter = GetFormatter();
1182  auto nScale = weld::SpinButton::Power10(rFormatter.GetDecimalDigits());
1183 
1184  sal_Int64 nValue = std::round(rFormatter.GetValue() * nScale);
1185  sal_Int64 nSpinSize = std::round(rFormatter.GetSpinSize() * nScale);
1186  sal_Int64 nRemainder = rFormatter.GetDisableRemainderFactor() ? 0 : nValue % nSpinSize;
1187  if (nValue >= 0)
1188  nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue + nSpinSize - nRemainder;
1189  else
1190  nValue = (nRemainder == 0) ? nValue + nSpinSize : nValue - nRemainder;
1191 
1192  // setValue handles under- and overflows (min/max) automatically
1193  rFormatter.SetValue(static_cast<double>(nValue) / nScale);
1194  SetModifyFlag();
1195  Modify();
1196 
1197  SpinField::Up();
1198 }
1199 
1201 {
1202  Formatter& rFormatter = GetFormatter();
1203  auto nScale = weld::SpinButton::Power10(rFormatter.GetDecimalDigits());
1204 
1205  sal_Int64 nValue = std::round(rFormatter.GetValue() * nScale);
1206  sal_Int64 nSpinSize = std::round(rFormatter.GetSpinSize() * nScale);
1207  sal_Int64 nRemainder = rFormatter.GetDisableRemainderFactor() ? 0 : nValue % nSpinSize;
1208  if (nValue >= 0)
1209  nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nRemainder;
1210  else
1211  nValue = (nRemainder == 0) ? nValue - nSpinSize : nValue - nSpinSize - nRemainder;
1212 
1213  // setValue handles under- and overflows (min/max) automatically
1214  rFormatter.SetValue(static_cast<double>(nValue) / nScale);
1215  SetModifyFlag();
1216  Modify();
1217 
1218  SpinField::Down();
1219 }
1220 
1222 {
1223  Formatter& rFormatter = GetFormatter();
1224  if (rFormatter.HasMinValue())
1225  {
1226  rFormatter.SetValue(rFormatter.GetMinValue());
1227  SetModifyFlag();
1228  Modify();
1229  }
1230 
1231  SpinField::First();
1232 }
1233 
1235 {
1236  Formatter& rFormatter = GetFormatter();
1237  if (rFormatter.HasMaxValue())
1238  {
1239  rFormatter.SetValue(rFormatter.GetMaxValue());
1240  SetModifyFlag();
1241  Modify();
1242  }
1243 
1244  SpinField::Last();
1245 }
1246 
1248 {
1249  GetFormatter().Modify();
1250 }
1251 
1253 {
1254  if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
1256  return SpinField::PreNotify(rNEvt);
1257 }
1258 
1260 {
1261  if ((rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !IsReadOnly())
1262  {
1263  const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
1264  sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
1265  switch ( rKEvt.GetKeyCode().GetCode() )
1266  {
1267  case KEY_UP:
1268  case KEY_DOWN:
1269  case KEY_PAGEUP:
1270  case KEY_PAGEDOWN:
1271  {
1272  Formatter& rFormatter = GetFormatter();
1273  if (!nMod && rFormatter.GetOrCreateFormatter()->IsTextFormat(rFormatter.GetFormatKey()))
1274  {
1275  // the base class would translate this into calls to Up/Down/First/Last,
1276  // but we don't want this if we are text-formatted
1277  return true;
1278  }
1279  }
1280  }
1281  }
1282 
1283  if ((rNEvt.GetType() == MouseNotifyEvent::COMMAND) && !IsReadOnly())
1284  {
1285  const CommandEvent* pCommand = rNEvt.GetCommandEvent();
1286  if (pCommand->GetCommand() == CommandEventId::Wheel)
1287  {
1288  const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
1289  Formatter& rFormatter = GetFormatter();
1290  if ((pData->GetMode() == CommandWheelMode::SCROLL) &&
1291  rFormatter.GetOrCreateFormatter()->IsTextFormat(rFormatter.GetFormatKey()))
1292  {
1293  // same as above : prevent the base class from doing Up/Down-calls
1294  // (normally I should put this test into the Up/Down methods itself, shouldn't I ?)
1295  // FS - 71553 - 19.01.00
1296  return true;
1297  }
1298  }
1299  }
1300 
1303 
1304  return SpinField::EventNotify( rNEvt );
1305 }
1306 
1308 {
1309  if (!m_pFormatter)
1310  {
1311  m_xOwnFormatter.reset(new FieldFormatter(*this));
1312  m_pFormatter = m_xOwnFormatter.get();
1313  }
1314  return *m_pFormatter;
1315 }
1316 
1318 {
1319  m_xOwnFormatter.reset();
1320  m_pFormatter = pFormatter;
1321 }
1322 
1323 // currently used by online
1324 void FormattedField::SetValueFromString(const OUString& rStr)
1325 {
1326  sal_Int32 nEnd;
1327  rtl_math_ConversionStatus eStatus;
1328  Formatter& rFormatter = GetFormatter();
1329  double fValue = ::rtl::math::stringToDouble(rStr, '.', rFormatter.GetDecimalDigits(), &eStatus, &nEnd );
1330 
1331  if (eStatus == rtl_math_ConversionStatus_Ok &&
1332  nEnd == rStr.getLength())
1333  {
1334  rFormatter.SetValue(fValue);
1335  SetModifyFlag();
1336  Modify();
1337 
1338  // Notify the value has changed
1339  SpinField::Up();
1340  }
1341  else
1342  {
1343  SAL_WARN("vcl", "fail to convert the value: " << rStr);
1344  }
1345 }
1346 
1348 {
1349  SpinField::DumpAsPropertyTree(rJsonWriter);
1350  Formatter& rFormatter = GetFormatter();
1351  rJsonWriter.put("min", rFormatter.GetMinValue());
1352  rJsonWriter.put("max", rFormatter.GetMaxValue());
1353  rJsonWriter.put("value", rFormatter.GetValue());
1354  rJsonWriter.put("step", rFormatter.GetSpinSize());
1355 }
1356 
1358 {
1360 }
1361 
1362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
tools::Long Max() const
static bool toBool(std::string_view rValue)
Definition: builder.cxx:89
void SetFormatKey(sal_uLong nFormatKey)
Definition: fmtfield.cxx:469
virtual bool set_property(const OString &rKey, const OUString &rValue) override
Definition: fmtfield.cxx:1168
bool HasMaxValue() const
Definition: formatter.hxx:167
void ImplSetFormatKey(sal_uLong nFormatKey)
Definition: fmtfield.cxx:451
static SvNumberFormatter * s_cFormatter
Definition: formatter.hxx:92
bool m_bHasMin
Definition: formatter.hxx:110
virtual void SetEntryText(const OUString &rText, const Selection &rSel)=0
static void lcl_insertStopTransition(StateTransitions &_rRow)
Definition: fmtfield.cxx:53
static void lcl_insertStartExponentTransition(StateTransitions &_rRow)
Definition: fmtfield.cxx:58
void SetFieldText(const OUString &rText, const Selection &rNewSelection)
Definition: fmtfield.cxx:287
double m_dSpinSize
Definition: formatter.hxx:129
const CommandEvent * GetCommandEvent() const
Definition: event.hxx:332
std::unique_ptr< ContentProperties > pData
void SetValueFromString(const OUString &rStr)
Definition: fmtfield.cxx:1324
void SetFormatter(Formatter *pFormatter)
Definition: fmtfield.cxx:1317
void Modify(bool makeValueDirty=true)
Definition: fmtfield.cxx:383
LanguageType getLanguageType(bool bResolveSystem=true) const
OString strip(std::string_view rIn, char c)
void SetDecimalDigits(sal_uInt16 _nPrecision)
Definition: fmtfield.cxx:599
SelectionOptions GetSelectionOptions() const
SelectionOptions
Definition: settings.hxx:178
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: fmtfield.cxx:1150
Formatter & GetFormatter()
Definition: fmtfield.cxx:1307
bool TreatingAsNumber() const
Definition: formatter.hxx:235
double m_dDefaultValue
Definition: formatter.hxx:123
sal_uIntPtr sal_uLong
#define SAL_INFO_IF(condition, area, stream)
const StyleSettings & GetStyleSettings() const
Selection m_aLastSelection
Definition: formatter.hxx:106
FORMAT_CHANGE_TYPE
Definition: formatter.hxx:76
virtual void Last() override
Definition: fmtfield.cxx:1234
void Commit()
reformats the current text.
Definition: fmtfield.cxx:668
std::function< std::unique_ptr< UIObject >vcl::Window *)> FactoryFunction
SvNumFormatType GetType(sal_uInt32 nFIndex) const
::std::map< sal_Unicode, State > StateTransitions
Definition: formatter.hxx:52
sal_uInt16 GetCode() const
Definition: keycod.hxx:49
virtual void SetEntryTextColor(const Color *pColor)=0
double m_dSpinFirst
Definition: formatter.hxx:130
virtual void SetText(const OUString &rStr) override
Definition: fmtfield.cxx:1157
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:316
bool IsUsingInputStringForFormatting() const
Definition: formatter.hxx:288
virtual void DumpAsPropertyTree(tools::JsonWriter &rJsonWriter) override
Dumps itself and potentially its children to a property tree, to be written easily to JSON...
Definition: edit.cxx:2916
virtual SelectionOptions GetEntrySelectionOptions() const =0
const sal_Int16 FORMATTEDFIELD
sal_uInt32 TestNewString(const OUString &sFormatString, LanguageType eLnge=LANGUAGE_DONTKNOW)
virtual bool set_property(const OString &rKey, const OUString &rValue) override
Definition: edit.cxx:181
void DisableRemainderFactor()
Definition: fmtfield.cxx:870
bool m_bUseInputStringForFormatting
Definition: formatter.hxx:143
virtual void First() override
Definition: fmtfield.cxx:1221
virtual void Up()
Definition: spinfld.cxx:357
virtual ~Formatter()
Definition: fmtfield.cxx:283
const CommandWheelData * GetWheelData() const
virtual OUString GetEntryText() const =0
TransitionTable m_aTransitions
Definition: formatter.hxx:64
TRISTATE_TRUE
virtual void SetMinValue(double dMin)
Definition: fmtfield.cxx:703
OUString m_sCurrentTextValue
Definition: formatter.hxx:137
const OUString & GetFormatstring() const
void EntryLostFocus()
Definition: fmtfield.cxx:638
void ReFormat()
Definition: fmtfield.cxx:687
constexpr sal_uInt16 KEY_UP
Definition: keycodes.hxx:111
bool IsEmptyFieldEnabled() const
Definition: formatter.hxx:180
void UseInputStringForFormatting()
When being set to true, the strings in the field are formatted using the InputLine format...
Definition: fmtfield.cxx:875
sal_Int64 WinBits
sal_uInt16 sal_Unicode
const LocaleDataWrapper & GetLocaleData() const
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: spinfld.cxx:350
StateTransitions::value_type Transition
Definition: formatter.hxx:55
bool PutEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bReplaceBooleanEquivalent=true)
virtual void Up() override
Definition: fmtfield.cxx:1179
static void lcl_insertSignTransitions(StateTransitions &_rRow, const State eNextState)
Definition: fmtfield.cxx:63
constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND
virtual void UpdateCurrentValue(double dCurrentValue)
Definition: formatter.hxx:313
double GetValue()
Definition: fmtfield.cxx:861
double m_dMinValue
Definition: formatter.hxx:108
bool m_bEnableNaN
Definition: formatter.hxx:118
constexpr sal_uInt16 KEY_PAGEUP
Definition: keycodes.hxx:116
bool m_bEnableEmptyField
Definition: formatter.hxx:116
virtual void SetModifyFlag()
Definition: edit.cxx:2586
bool m_bStrictFormat
Definition: formatter.hxx:114
bool m_bDisableRemainderFactor
Definition: formatter.hxx:119
double GetSpinSize() const
Definition: formatter.hxx:227
virtual const Selection & GetSelection() const
Definition: edit.cxx:2466
sal_uInt16 GetModifier() const
Definition: keycod.hxx:52
void SetAutoColor(bool _bAutomatic)
Definition: fmtfield.cxx:370
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: fmtfield.cxx:1259
void GetFormatSpecialInfo(sal_uInt32 nFormat, bool &bThousand, bool &IsRed, sal_uInt16 &nPrecision, sal_uInt16 &nLeadingCnt)
virtual void Down()
Definition: spinfld.cxx:362
Formatter * m_pFormatter
Definition: fmtfield.hxx:60
TRISTATE_INDET
virtual void SetSelection(const Selection &rSelection)
Definition: edit.cxx:2392
void SetTextFormatted(const OUString &rText)
Definition: fmtfield.cxx:293
virtual void Modify() override
Definition: fmtfield.cxx:1247
const Color * m_pLastOutputColor
Definition: formatter.hxx:141
void SetFormatter(SvNumberFormatter *pFormatter, bool bResetFormat=true)
Definition: fmtfield.cxx:476
constexpr sal_uInt16 KEY_DOWN
Definition: keycodes.hxx:110
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:483
void Justify()
double GetMaxValue() const
Definition: formatter.hxx:170
#define DBG_ASSERT(sCon, aError)
virtual void Down() override
Definition: fmtfield.cxx:1200
sal_uLong GetFormatKey() const
Definition: formatter.hxx:191
void SetValue(double dVal)
Definition: fmtfield.cxx:856
OUString const & GetTextValue() const
Definition: fmtfield.cxx:352
bool IsTextFormat(sal_uInt32 nFIndex) const
void SetControlForeground()
Definition: window2.cxx:451
virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat)
Definition: fmtfield.cxx:628
CommandWheelMode GetMode() const
virtual OUString GetText() const override
Definition: edit.cxx:2562
virtual Selection GetEntrySelection() const =0
const AllSettings & GetSettings() const
Definition: window3.cxx:129
void ImplSetTextImpl(const OUString &rNew, Selection const *pNewSel)
Definition: fmtfield.cxx:409
CommandEventId GetCommand() const
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
void SetEvalDateFormat(NfEvalDateFormat eEDF)
void GetInputLineString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &rOutString, bool bFiltering=false)
constexpr sal_uInt16 KEY_PAGEDOWN
Definition: keycodes.hxx:117
bool m_bTreatAsNumber
Definition: formatter.hxx:135
virtual FactoryFunction GetUITestFactory() const override
Definition: fmtfield.cxx:1357
#define LANGUAGE_DONTKNOW
SvNumFormatType
MouseNotifyEvent GetType() const
Definition: event.hxx:308
SvNumberFormatter * m_pFormatter
Definition: formatter.hxx:126
bool implValidateNormalized(const OUString &_rText)
Definition: fmtfield.cxx:175
bool PreNotify(NotifyEvent &rNEvt) override
Definition: fmtfield.cxx:1252
virtual void DumpAsPropertyTree(tools::JsonWriter &) override
Dumps itself and potentially its children to a property tree, to be written easily to JSON...
Definition: fmtfield.cxx:1347
virtual void SetMaxValue(double dMax)
Definition: fmtfield.cxx:713
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
void put(const char *pPropName, const OUString &rPropValue)
void SetTextValue(const OUString &rText)
Definition: fmtfield.cxx:723
bool PutandConvertEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge, LanguageType eNewLnge, bool bConvertDateOrder, bool bReplaceBooleanEquivalent=true)
void ImplSetValue(double dValue, bool bForce)
Definition: fmtfield.cxx:739
OUString GetFormat(LanguageType &eLang) const
Definition: fmtfield.cxx:518
bool m_bWrapOnLimits
Definition: formatter.hxx:113
const OUString & getCurrSymbol() const
static void lcl_insertDigitTransitions(StateTransitions &_rRow, const State eNextState)
Definition: fmtfield.cxx:69
OUString GenerateFormat(sal_uInt32 nIndex, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bThousand=false, bool IsRed=false, sal_uInt16 nPrecision=0, sal_uInt16 nLeadingCnt=1)
double m_dMaxValue
Definition: formatter.hxx:109
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:57
valueState m_ValueState
Definition: formatter.hxx:121
virtual void First()
Definition: spinfld.cxx:367
bool m_bAutoColor
Definition: formatter.hxx:117
OUString m_sLastValidText
Definition: formatter.hxx:103
virtual void FieldModified()=0
void SetThousandsSep(bool _bUseSeparator)
Definition: fmtfield.cxx:558
bool GetDisableRemainderFactor() const
Definition: formatter.hxx:206
std::unique_ptr< Formatter > m_xOwnFormatter
Definition: fmtfield.hxx:59
WindowType
bool GetThousandsSep() const
Definition: fmtfield.cxx:546
double m_dSpinLast
Definition: formatter.hxx:131
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
tools::Long Min() const
NumberValidator(const sal_Unicode _cThSep, const sal_Unicode _cDecSep)
Definition: fmtfield.cxx:87
double m_dCurrentValue
Definition: formatter.hxx:122
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
bool HasMinValue() const
Definition: formatter.hxx:162
void SetWrapOnLimits(bool bWrapOnLimits)
Definition: formatter.hxx:208
sal_uInt16 GetDecimalDigits() const
Definition: fmtfield.cxx:587
virtual void Last()
Definition: spinfld.cxx:372
Link< sal_Int64 *, TriState > m_aInputHdl
Definition: formatter.hxx:145
Reference< XComponentContext > getProcessComponentContext()
QPRO_FUNC_TYPE nType
virtual bool CheckText(const OUString &) const
Definition: formatter.hxx:302
void SetLastSelection(const Selection &rSelection)
Definition: formatter.hxx:188
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:831
bool m_bHasMax
Definition: formatter.hxx:111
static sal_uLong s_nReferences
Definition: formatter.hxx:93
void EnableEmptyField(bool bEnable)
Definition: fmtfield.cxx:729
void EnableNotANumber(bool _bEnable)
enables handling of not-a-number value.
Definition: fmtfield.cxx:362
SvNumberFormatter * GetOrCreateFormatter() const
Definition: formatter.hxx:194
OUString m_sDefaultText
Definition: formatter.hxx:138
bool SetFormat(const OUString &rFormatString, LanguageType eLang)
Definition: fmtfield.cxx:528
double GetMinValue() const
Definition: formatter.hxx:165
const LanguageTag & GetLanguageTag() const
#define SAL_WARN(area, stream)
bool ImplGetValue(double &dNewVal)
Definition: fmtfield.cxx:788
virtual bool IsReadOnly() const
Definition: edit.hxx:175
bool IsStrictFormat() const
Definition: formatter.hxx:222
static unsigned int Power10(unsigned int n)
Definition: builder.cxx:263
NF_EVALDATEFORMAT_FORMAT_INTL
FormattedField(vcl::Window *pParent, WinBits nStyle)
Definition: fmtfield.cxx:1144
bool isValidNumericFragment(std::u16string_view _rText)
Definition: fmtfield.cxx:214
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
sal_uLong m_nFormatKey
Definition: formatter.hxx:125
LanguageType GetLanguage() const
sal_Int16 nValue
void SetFormat(LotusContext &rContext, SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt8 nFormat, sal_uInt8 nSt)
Link< LinkParamNone *, bool > m_aOutputHdl
Definition: formatter.hxx:146
static void lcl_insertCommonPreCommaTransitions(StateTransitions &_rRow, const sal_Unicode _cThSep, const sal_Unicode _cDecSep)
Definition: fmtfield.cxx:75
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill= '\0')