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