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