xref: /trunk/main/svtools/source/control/fmtfield.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svtools.hxx"
30 
31 #include <stdio.h>
32 #include <tools/debug.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <unotools/localedatawrapper.hxx>
35 #include <vcl/svapp.hxx>
36 #include <svl/zformat.hxx>
37 #include <svtools/fmtfield.hxx>
38 #include <i18npool/mslangid.hxx>
39 #include <com/sun/star/lang/Locale.hpp>
40 #include <com/sun/star/util/SearchOptions.hpp>
41 #include <com/sun/star/util/SearchAlgorithms.hpp>
42 #include <com/sun/star/util/SearchResult.hpp>
43 #include <com/sun/star/util/SearchFlags.hpp>
44 #include <com/sun/star/lang/Locale.hpp>
45 #include <unotools/syslocale.hxx>
46 
47 #ifndef REGEXP_SUPPORT
48 #include <map>
49 #endif
50 
51 #if !defined INCLUDED_RTL_MATH_HXX
52 #include <rtl/math.hxx>
53 #endif
54 
55 using namespace ::com::sun::star::lang;
56 using namespace ::com::sun::star::util;
57 
58 
59 #ifdef REGEXP_SUPPORT
60 
61 //==============================================================================
62 // regular expression to validate complete numbers, plus every fragment which can occur during the input
63 // of a complete number
64 // [+/-][{digit}*.]*{digit}*[,{digit}*][e[+/-]{digit}*]
65 const char __FAR_DATA szNumericInput[] = "_[-+]?([0-9]*\\,)*[0-9]*(\\.[0-9]*)?(e[-+]?[0-9]*)?_";
66     // (the two _ are for normalizing it: With this, we can ensure that a to-be-checked text is always
67     // matched as a _whole_)
68 #else
69 
70 // hmm. No support for regular expression. Well, I always (not really :) wanted to write a finite automat
71 // so here comes a finite automat ...
72 
73 namespace validation
74 {
75     // the states of our automat.
76     enum State
77     {
78         START,              // at the very start of the string
79         NUM_START,          // the very start of the number
80 
81         DIGIT_PRE_COMMA,    // some pre-comma digits are read, perhaps including some thousand separators
82 
83         DIGIT_POST_COMMA,   // reading digits after the comma
84         EXPONENT_START,     // at the very start of the exponent value
85                             //    (means: not including the "e" which denotes the exponent)
86         EXPONENT_DIGIT,     // currently reading the digits of the exponent
87 
88         END                 // reached the end of the string
89     };
90 
91     // a row in the transition table (means the set of states to be reached from a given state)
92     typedef ::std::map< sal_Unicode, State >        StateTransitions;
93 
94     // a single transition
95     typedef StateTransitions::value_type            Transition;
96 
97     // the complete transition table
98     typedef ::std::map< State, StateTransitions >   TransitionTable;
99 
100     // the validator class
101     class NumberValidator
102     {
103     private:
104         TransitionTable     m_aTransitions;
105         const sal_Unicode   m_cThSep;
106         const sal_Unicode   m_cDecSep;
107 
108     public:
109         NumberValidator( const sal_Unicode _cThSep, const sal_Unicode _cDecSep );
110 
111         sal_Bool isValidNumericFragment( const String& _rText );
112 
113     private:
114         sal_Bool implValidateNormalized( const String& _rText );
115     };
116 
117     //--------------------------------------------------------------------------
118     //..........................................................................
119     static void lcl_insertStopTransition( StateTransitions& _rRow )
120     {
121         _rRow.insert( Transition( '_', END ) );
122     }
123 
124     //..........................................................................
125     static void lcl_insertStartExponentTransition( StateTransitions& _rRow )
126     {
127         _rRow.insert( Transition( 'e', EXPONENT_START ) );
128     }
129 
130     //..........................................................................
131     static void lcl_insertSignTransitions( StateTransitions& _rRow, const State eNextState )
132     {
133         _rRow.insert( Transition( '-', eNextState ) );
134         _rRow.insert( Transition( '+', eNextState ) );
135     }
136 
137     //..........................................................................
138     static void lcl_insertDigitTransitions( StateTransitions& _rRow, const State eNextState )
139     {
140         for ( sal_Unicode aChar = '0'; aChar <= '9'; ++aChar )
141             _rRow.insert( Transition( aChar, eNextState ) );
142     }
143 
144     //..........................................................................
145     static void lcl_insertCommonPreCommaTransitions( StateTransitions& _rRow, const sal_Unicode _cThSep, const sal_Unicode _cDecSep )
146     {
147         // digits are allowed
148         lcl_insertDigitTransitions( _rRow, DIGIT_PRE_COMMA );
149 
150         // the thousand separator is allowed
151         _rRow.insert( Transition( _cThSep, DIGIT_PRE_COMMA ) );
152 
153         // a comma is allowed
154         _rRow.insert( Transition( _cDecSep, DIGIT_POST_COMMA ) );
155     }
156 
157     //--------------------------------------------------------------------------
158     NumberValidator::NumberValidator( const sal_Unicode _cThSep, const sal_Unicode _cDecSep )
159         :m_cThSep( _cThSep )
160         ,m_cDecSep( _cDecSep )
161     {
162         // build up our transition table
163 
164         // how to procede from START
165         {
166             StateTransitions& rRow = m_aTransitions[ START ];
167             rRow.insert( Transition( '_', NUM_START ) );
168                 // if we encounter the normalizing character, we want to procede with the number
169         }
170 
171         // how to procede from NUM_START
172         {
173             StateTransitions& rRow = m_aTransitions[ NUM_START ];
174 
175             // a sign is allowed
176             lcl_insertSignTransitions( rRow, DIGIT_PRE_COMMA );
177 
178             // common transitions for the two pre-comma states
179             lcl_insertCommonPreCommaTransitions( rRow, m_cThSep, m_cDecSep );
180 
181             // the exponent may start here
182             // (this would mean string like "_+e10_", but this is a valid fragment, though no valid number)
183             lcl_insertStartExponentTransition( rRow );
184         }
185 
186         // how to procede from DIGIT_PRE_COMMA
187         {
188             StateTransitions& rRow = m_aTransitions[ DIGIT_PRE_COMMA ];
189 
190             // common transitions for the two pre-comma states
191             lcl_insertCommonPreCommaTransitions( rRow, m_cThSep, m_cDecSep );
192 
193             // the exponent may start here
194             lcl_insertStartExponentTransition( rRow );
195 
196             // the final transition indicating the end of the string
197             // (if there is no comma and no post-comma, then the string may end here)
198             lcl_insertStopTransition( rRow );
199         }
200 
201         // how to procede from DIGIT_POST_COMMA
202         {
203             StateTransitions& rRow = m_aTransitions[ DIGIT_POST_COMMA ];
204 
205             // there might be digits, which would keep the state at DIGIT_POST_COMMA
206             lcl_insertDigitTransitions( rRow, DIGIT_POST_COMMA );
207 
208             // the exponent may start here
209             lcl_insertStartExponentTransition( rRow );
210 
211             // the string may end here
212             lcl_insertStopTransition( rRow );
213         }
214 
215         // how to procede from EXPONENT_START
216         {
217             StateTransitions& rRow = m_aTransitions[ EXPONENT_START ];
218 
219             // there may be a sign
220             lcl_insertSignTransitions( rRow, EXPONENT_DIGIT );
221 
222             // there may be digits
223             lcl_insertDigitTransitions( rRow, EXPONENT_DIGIT );
224 
225             // the string may end here
226             lcl_insertStopTransition( rRow );
227         }
228 
229         // how to procede from EXPONENT_DIGIT
230         {
231             StateTransitions& rRow = m_aTransitions[ EXPONENT_DIGIT ];
232 
233             // there may be digits
234             lcl_insertDigitTransitions( rRow, EXPONENT_DIGIT );
235 
236             // the string may end here
237             lcl_insertStopTransition( rRow );
238         }
239 
240         // how to procede from END
241         {
242             /*StateTransitions& rRow =*/ m_aTransitions[ EXPONENT_DIGIT ];
243             // no valid transition to leave this state
244             // (note that we, for consistency, nevertheless want to have a row in the table)
245         }
246     }
247 
248     //--------------------------------------------------------------------------
249     sal_Bool NumberValidator::implValidateNormalized( const String& _rText )
250     {
251         const sal_Unicode* pCheckPos = _rText.GetBuffer();
252         State eCurrentState = START;
253 
254         while ( END != eCurrentState )
255         {
256             // look up the transition row for the current state
257             TransitionTable::const_iterator aRow = m_aTransitions.find( eCurrentState );
258             DBG_ASSERT( m_aTransitions.end() != aRow,
259                 "NumberValidator::implValidateNormalized: invalid transition table (row not found)!" );
260 
261             if ( m_aTransitions.end() != aRow )
262             {
263                 // look up the current character in this row
264                 StateTransitions::const_iterator aTransition = aRow->second.find( *pCheckPos );
265                 if ( aRow->second.end() != aTransition )
266                 {
267                     // there is a valid transition for this character
268                     eCurrentState = aTransition->second;
269                     ++pCheckPos;
270                     continue;
271                 }
272             }
273 
274             // if we're here, there is no valid transition
275             break;
276         }
277 
278         DBG_ASSERT( ( END != eCurrentState ) || ( 0 == *pCheckPos ),
279             "NumberValidator::implValidateNormalized: inconsistency!" );
280             // if we're at END, then the string should be done, too - the string should be normalized, means ending
281             // a "_" and not containing any other "_" (except at the start), and "_" is the only possibility
282             // to reach the END state
283 
284         // the string is valid if and only if we reached the final state
285         return ( END == eCurrentState );
286     }
287 
288     //--------------------------------------------------------------------------
289     sal_Bool NumberValidator::isValidNumericFragment( const String& _rText )
290     {
291         if ( !_rText.Len() )
292             // empty strings are always allowed
293             return sal_True;
294 
295         // normalize the string
296         String sNormalized( RTL_CONSTASCII_STRINGPARAM( "_") );
297         sNormalized.Append( _rText );
298         sNormalized.AppendAscii( "_" );
299 
300         return implValidateNormalized( sNormalized );
301     }
302 }
303 
304 #endif
305 
306 //==============================================================================
307 SvNumberFormatter* FormattedField::StaticFormatter::s_cFormatter = NULL;
308 sal_uLong FormattedField::StaticFormatter::s_nReferences = 0;
309 
310 //------------------------------------------------------------------------------
311 SvNumberFormatter* FormattedField::StaticFormatter::GetFormatter()
312 {
313     if (!s_cFormatter)
314     {
315         // get the Office's locale and translate
316         LanguageType eSysLanguage = MsLangId::convertLocaleToLanguage(
317                 SvtSysLocale().GetLocaleData().getLocale() );
318         s_cFormatter = new SvNumberFormatter(
319             ::comphelper::getProcessServiceFactory(),
320             eSysLanguage);
321     }
322     return s_cFormatter;
323 }
324 
325 //------------------------------------------------------------------------------
326 FormattedField::StaticFormatter::StaticFormatter()
327 {
328     ++s_nReferences;
329 }
330 
331 //------------------------------------------------------------------------------
332 FormattedField::StaticFormatter::~StaticFormatter()
333 {
334     if (--s_nReferences == 0)
335     {
336         delete s_cFormatter;
337         s_cFormatter = NULL;
338     }
339 }
340 
341 //==============================================================================
342 DBG_NAME(FormattedField);
343 
344 #define INIT_MEMBERS()              \
345      m_aLastSelection(0,0)          \
346     ,m_dMinValue(0)                 \
347     ,m_dMaxValue(0)                 \
348     ,m_bHasMin(sal_False)               \
349     ,m_bHasMax(sal_False)               \
350     ,m_bStrictFormat(sal_True)          \
351     ,m_bValueDirty(sal_True)            \
352     ,m_bEnableEmptyField(sal_True)      \
353     ,m_bAutoColor(sal_False)            \
354     ,m_bEnableNaN(sal_False)            \
355     ,m_dCurrentValue(0)             \
356     ,m_dDefaultValue(0)             \
357     ,m_nFormatKey(0)                \
358     ,m_pFormatter(NULL)             \
359     ,m_dSpinSize(1)                 \
360     ,m_dSpinFirst(-1000000)         \
361     ,m_dSpinLast(1000000)           \
362     ,m_bTreatAsNumber(sal_True)         \
363     ,m_pLastOutputColor(NULL)       \
364     ,m_bUseInputStringForFormatting(false)
365 
366 //------------------------------------------------------------------------------
367 FormattedField::FormattedField(Window* pParent, WinBits nStyle, SvNumberFormatter* pInitialFormatter, sal_Int32 nFormatKey)
368     :SpinField(pParent, nStyle)
369     ,INIT_MEMBERS()
370 {
371     DBG_CTOR(FormattedField, NULL);
372 
373     if (pInitialFormatter)
374     {
375         m_pFormatter = pInitialFormatter;
376         m_nFormatKey = nFormatKey;
377     }
378 }
379 
380 //------------------------------------------------------------------------------
381 FormattedField::FormattedField(Window* pParent, const ResId& rResId, SvNumberFormatter* pInitialFormatter, sal_Int32 nFormatKey)
382     :SpinField(pParent, rResId)
383     ,INIT_MEMBERS()
384 {
385     DBG_CTOR(FormattedField, NULL);
386 
387     if (pInitialFormatter)
388     {
389         m_pFormatter = pInitialFormatter;
390         m_nFormatKey = nFormatKey;
391     }
392 }
393 
394 //------------------------------------------------------------------------------
395 FormattedField::~FormattedField()
396 {
397     DBG_DTOR(FormattedField, NULL);
398 }
399 
400 //------------------------------------------------------------------------------
401 void FormattedField::SetValidateText(const XubString& rText, const String* pErrorText)
402 {
403     DBG_CHKTHIS(FormattedField, NULL);
404 
405     if (CheckText(rText))
406         SetText(rText);
407     else
408         if (pErrorText)
409             ImplSetTextImpl(*pErrorText, NULL);
410         else
411             ImplSetValue(m_dDefaultValue, sal_True);
412 }
413 
414 //------------------------------------------------------------------------------
415 void FormattedField::SetText(const XubString& rStr)
416 {
417     DBG_CHKTHIS(FormattedField, NULL);
418 
419     SpinField::SetText(rStr);
420     m_bValueDirty = sal_True;
421 }
422 
423 //------------------------------------------------------------------------------
424 void FormattedField::SetText( const XubString& rStr, const Selection& rNewSelection )
425 {
426     DBG_CHKTHIS(FormattedField, NULL);
427 
428     SpinField::SetText( rStr, rNewSelection );
429     m_bValueDirty = sal_True;
430 }
431 
432 //------------------------------------------------------------------------------
433 void FormattedField::SetTextFormatted(const XubString& rStr)
434 {
435     DBG_CHKTHIS(FormattedField, NULL);
436 
437 #if defined DBG_UTIL
438     if (ImplGetFormatter()->IsTextFormat(m_nFormatKey))
439          DBG_WARNING("FormattedField::SetTextFormatted : valid only with text formats !");
440 #endif
441 
442     m_sCurrentTextValue = rStr;
443 
444     String sFormatted;
445     double dNumber = 0.0;
446     // IsNumberFormat changes the format key parameter
447     sal_uInt32 nTempFormatKey = static_cast< sal_uInt32 >( m_nFormatKey );
448     if( IsUsingInputStringForFormatting() &&
449         ImplGetFormatter()->IsNumberFormat(m_sCurrentTextValue, nTempFormatKey, dNumber) )
450         ImplGetFormatter()->GetInputLineString(dNumber, m_nFormatKey, sFormatted);
451     else
452         ImplGetFormatter()->GetOutputString(m_sCurrentTextValue, m_nFormatKey, sFormatted, &m_pLastOutputColor);
453 
454     // calculate the new selection
455     Selection aSel(GetSelection());
456     Selection aNewSel(aSel);
457     aNewSel.Justify();
458     sal_uInt16 nNewLen = sFormatted.Len();
459     sal_uInt16 nCurrentLen = GetText().Len();
460     if ((nNewLen > nCurrentLen) && (aNewSel.Max() == nCurrentLen))
461     {   // the new text is longer and the cursor was behind the last char (of the old text)
462         if (aNewSel.Min() == 0)
463         {   // the whole text was selected -> select the new text on the whole, too
464             aNewSel.Max() = nNewLen;
465             if (!nCurrentLen)
466             {   // there wasn't really a previous selection (as there was no previous text), we're setting a new one -> check the selection options
467                 sal_uLong nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
468                 if (nSelOptions & SELECTION_OPTION_SHOWFIRST)
469                 {   // selection should be from right to left -> swap min and max
470                     aNewSel.Min() = aNewSel.Max();
471                     aNewSel.Max() = 0;
472                 }
473             }
474         }
475         else if (aNewSel.Max() == aNewSel.Min())
476         {   // there was no selection -> set the cursor behind the new last char
477             aNewSel.Max() = nNewLen;
478             aNewSel.Min() = nNewLen;
479         }
480     }
481     else if (aNewSel.Max() > nNewLen)
482         aNewSel.Max() = nNewLen;
483     else
484         aNewSel = aSel; // don't use the justified version
485     SpinField::SetText(sFormatted, aNewSel);
486     m_bValueDirty = sal_False;
487 }
488 
489 //------------------------------------------------------------------------------
490 String FormattedField::GetTextValue() const
491 {
492     if (m_bValueDirty)
493     {
494         ((FormattedField*)this)->m_sCurrentTextValue = GetText();
495         ((FormattedField*)this)->m_bValueDirty = sal_False;
496     }
497     return m_sCurrentTextValue;
498 }
499 
500 //------------------------------------------------------------------------------
501 void FormattedField::EnableNotANumber( sal_Bool _bEnable )
502 {
503     if ( m_bEnableNaN == _bEnable )
504         return;
505 
506     m_bEnableNaN = _bEnable;
507 }
508 
509 //------------------------------------------------------------------------------
510 void FormattedField::SetAutoColor(sal_Bool _bAutomatic)
511 {
512     if (_bAutomatic == m_bAutoColor)
513         return;
514 
515     m_bAutoColor = _bAutomatic;
516     if (m_bAutoColor)
517     {   // if auto color is switched on, adjust the current text color, too
518         if (m_pLastOutputColor)
519             SetControlForeground(*m_pLastOutputColor);
520         else
521             SetControlForeground();
522     }
523 }
524 
525 //------------------------------------------------------------------------------
526 void FormattedField::Modify()
527 {
528     DBG_CHKTHIS(FormattedField, NULL);
529 
530     if (!IsStrictFormat())
531     {
532         m_bValueDirty = sal_True;
533         SpinField::Modify();
534         return;
535     }
536 
537     String sCheck = GetText();
538     if (CheckText(sCheck))
539     {
540         m_sLastValidText = sCheck;
541         m_aLastSelection = GetSelection();
542         m_bValueDirty = sal_True;
543     }
544     else
545     {
546         ImplSetTextImpl(m_sLastValidText, &m_aLastSelection);
547     }
548 
549     SpinField::Modify();
550 }
551 
552 //------------------------------------------------------------------------------
553 void FormattedField::ImplSetTextImpl(const XubString& rNew, Selection* pNewSel)
554 {
555     DBG_CHKTHIS(FormattedField, NULL);
556 
557     if (m_bAutoColor)
558     {
559         if (m_pLastOutputColor)
560             SetControlForeground(*m_pLastOutputColor);
561         else
562             SetControlForeground();
563     }
564 
565     if (pNewSel)
566         SpinField::SetText(rNew, *pNewSel);
567     else
568     {
569         Selection aSel(GetSelection());
570         aSel.Justify();
571 
572         sal_uInt16 nNewLen = rNew.Len();
573         sal_uInt16 nCurrentLen = GetText().Len();
574 
575         if ((nNewLen > nCurrentLen) && (aSel.Max() == nCurrentLen))
576         {   // new new text is longer and the cursor is behind the last char
577             if (aSel.Min() == 0)
578             {   // the whole text was selected -> select the new text on the whole, too
579                 aSel.Max() = nNewLen;
580                 if (!nCurrentLen)
581                 {   // there wasn't really a previous selection (as there was no previous text), we're setting a new one -> check the selection options
582                     sal_uLong nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
583                     if (nSelOptions & SELECTION_OPTION_SHOWFIRST)
584                     {   // selection should be from right to left -> swap min and max
585                         aSel.Min() = aSel.Max();
586                         aSel.Max() = 0;
587                     }
588                 }
589             }
590             else if (aSel.Max() == aSel.Min())
591             {   // there was no selection -> set the cursor behind the new last char
592                 aSel.Max() = nNewLen;
593                 aSel.Min() = nNewLen;
594             }
595         }
596         else if (aSel.Max() > nNewLen)
597             aSel.Max() = nNewLen;
598         SpinField::SetText(rNew, aSel);
599     }
600 
601     m_bValueDirty = sal_True;
602         // muss nicht stimmen, aber sicherheitshalber ...
603 }
604 
605 //------------------------------------------------------------------------------
606 long FormattedField::PreNotify(NotifyEvent& rNEvt)
607 {
608     DBG_CHKTHIS(FormattedField, NULL);
609     if (rNEvt.GetType() == EVENT_KEYINPUT)
610         m_aLastSelection = GetSelection();
611     return SpinField::PreNotify(rNEvt);
612 }
613 
614 //------------------------------------------------------------------------------
615 void FormattedField::ImplSetFormatKey(sal_uLong nFormatKey)
616 {
617     DBG_CHKTHIS(FormattedField, NULL);
618 
619     m_nFormatKey = nFormatKey;
620     sal_Bool bNeedFormatter = (m_pFormatter == NULL) && (nFormatKey != 0);
621     if (bNeedFormatter)
622     {
623         ImplGetFormatter();     // damit wird ein Standard-Formatter angelegt
624 
625         m_nFormatKey = nFormatKey;
626             // kann sein, dass das in dem Standard-Formatter keinen Sinn macht, aber der nimmt dann ein Default-Format an.
627             // Auf diese Weise kann ich einfach einen der - formatteruebergreifended gleichen - Standard-Keys setzen.
628         DBG_ASSERT(m_pFormatter->GetEntry(nFormatKey) != NULL, "FormattedField::ImplSetFormatKey : invalid format key !");
629             // Wenn SetFormatKey aufgerufen wird, ohne dass ein Formatter existiert, muss der Key einer der Standard-Werte
630             // sein, der in allen Formattern (also auch in meinem neu angelegten) vorhanden ist.
631     }
632 }
633 
634 //------------------------------------------------------------------------------
635 void FormattedField::SetFormatKey(sal_uLong nFormatKey)
636 {
637     DBG_CHKTHIS(FormattedField, NULL);
638     sal_Bool bNoFormatter = (m_pFormatter == NULL);
639     ImplSetFormatKey(nFormatKey);
640     FormatChanged((bNoFormatter && (m_pFormatter != NULL)) ? FCT_FORMATTER : FCT_KEYONLY);
641 }
642 
643 //------------------------------------------------------------------------------
644 void FormattedField::SetFormatter(SvNumberFormatter* pFormatter, sal_Bool bResetFormat)
645 {
646     DBG_CHKTHIS(FormattedField, NULL);
647 
648     if (bResetFormat)
649     {
650         m_pFormatter = pFormatter;
651 
652         // calc the default format key from the Office's UI locale
653         if ( m_pFormatter )
654         {
655             // get the Office's locale and translate
656             LanguageType eSysLanguage = MsLangId::convertLocaleToLanguage(
657                     SvtSysLocale().GetLocaleData().getLocale() );
658             // get the standard numeric format for this language
659             m_nFormatKey = m_pFormatter->GetStandardFormat( NUMBERFORMAT_NUMBER, eSysLanguage );
660         }
661         else
662             m_nFormatKey = 0;
663     }
664     else
665     {
666         XubString sOldFormat;
667         LanguageType aOldLang;
668         GetFormat(sOldFormat, aOldLang);
669 
670         sal_uInt32 nDestKey = pFormatter->TestNewString(sOldFormat);
671         if (nDestKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
672         {
673             // die Sprache des neuen Formatters
674             const SvNumberformat* pDefaultEntry = pFormatter->GetEntry(0);
675             LanguageType aNewLang = pDefaultEntry ? pDefaultEntry->GetLanguage() : LANGUAGE_DONTKNOW;
676 
677             // den alten Format-String in die neue Sprache konvertieren
678             sal_uInt16 nCheckPos;
679             short nType;
680             pFormatter->PutandConvertEntry(sOldFormat, nCheckPos, nType, nDestKey, aOldLang, aNewLang);
681             m_nFormatKey = nDestKey;
682         }
683         m_pFormatter = pFormatter;
684     }
685 
686     FormatChanged(FCT_FORMATTER);
687 }
688 
689 //------------------------------------------------------------------------------
690 void FormattedField::GetFormat(XubString& rFormatString, LanguageType& eLang) const
691 {
692     DBG_CHKTHIS(FormattedField, NULL);
693     const SvNumberformat* pFormatEntry = ImplGetFormatter()->GetEntry(m_nFormatKey);
694     DBG_ASSERT(pFormatEntry != NULL, "FormattedField::GetFormat: no number format for the given format key.");
695     rFormatString = pFormatEntry ? pFormatEntry->GetFormatstring() : XubString();
696     eLang = pFormatEntry ? pFormatEntry->GetLanguage() : LANGUAGE_DONTKNOW;
697 }
698 
699 //------------------------------------------------------------------------------
700 sal_Bool FormattedField::SetFormat(const XubString& rFormatString, LanguageType eLang)
701 {
702     DBG_CHKTHIS(FormattedField, NULL);
703     sal_uInt32 nNewKey = ImplGetFormatter()->TestNewString(rFormatString, eLang);
704     if (nNewKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
705     {
706         sal_uInt16 nCheckPos;
707         short nType;
708         XubString rFormat(rFormatString);
709         if (!ImplGetFormatter()->PutEntry(rFormat, nCheckPos, nType, nNewKey, eLang))
710             return sal_False;
711         DBG_ASSERT(nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND, "FormattedField::SetFormatString : PutEntry returned an invalid key !");
712     }
713 
714     if (nNewKey != m_nFormatKey)
715         SetFormatKey(nNewKey);
716     return sal_True;
717 }
718 
719 //------------------------------------------------------------------------------
720 sal_Bool FormattedField::GetThousandsSep() const
721 {
722     DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
723         "FormattedField::GetThousandsSep : your'e sure what your'e doing when setting the precision of a text format ?");
724 
725     sal_Bool bThousand, IsRed;
726     sal_uInt16 nPrecision, nAnzLeading;
727     ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading);
728 
729     return bThousand;
730 }
731 
732 //------------------------------------------------------------------------------
733 void FormattedField::SetThousandsSep(sal_Bool _bUseSeparator)
734 {
735     DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
736         "FormattedField::SetThousandsSep : your'e sure what your'e doing when setting the precision of a text format ?");
737 
738     // get the current settings
739     sal_Bool bThousand, IsRed;
740     sal_uInt16 nPrecision, nAnzLeading;
741     ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading);
742     if (bThousand == _bUseSeparator)
743         return;
744 
745     // we need the language for the following
746     LanguageType eLang;
747     String sFmtDescription;
748     GetFormat(sFmtDescription, eLang);
749 
750     // generate a new format ...
751     ImplGetFormatter()->GenerateFormat(sFmtDescription, m_nFormatKey, eLang, _bUseSeparator, IsRed, nPrecision, nAnzLeading);
752     // ... and introduce it to the formatter
753     sal_uInt16 nCheckPos;
754     sal_uInt32  nNewKey;
755     short nType;
756     ImplGetFormatter()->PutEntry(sFmtDescription, nCheckPos, nType, nNewKey, eLang);
757 
758     // set the new key
759     ImplSetFormatKey(nNewKey);
760     FormatChanged(FCT_THOUSANDSSEP);
761 }
762 
763 //------------------------------------------------------------------------------
764 sal_uInt16 FormattedField::GetDecimalDigits() const
765 {
766     DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
767         "FormattedField::GetDecimalDigits : your'e sure what your'e doing when setting the precision of a text format ?");
768 
769     sal_Bool bThousand, IsRed;
770     sal_uInt16 nPrecision, nAnzLeading;
771     ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading);
772 
773     return nPrecision;
774 }
775 
776 //------------------------------------------------------------------------------
777 void FormattedField::SetDecimalDigits(sal_uInt16 _nPrecision)
778 {
779     DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
780         "FormattedField::SetDecimalDigits : your'e sure what your'e doing when setting the precision of a text format ?");
781 
782     // get the current settings
783     sal_Bool bThousand, IsRed;
784     sal_uInt16 nPrecision, nAnzLeading;
785     ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading);
786     if (nPrecision == _nPrecision)
787         return;
788 
789     // we need the language for the following
790     LanguageType eLang;
791     String sFmtDescription;
792     GetFormat(sFmtDescription, eLang);
793 
794     // generate a new format ...
795     ImplGetFormatter()->GenerateFormat(sFmtDescription, m_nFormatKey, eLang, bThousand, IsRed, _nPrecision, nAnzLeading);
796     // ... and introduce it to the formatter
797     sal_uInt16 nCheckPos;
798     sal_uInt32 nNewKey;
799     short nType;
800     ImplGetFormatter()->PutEntry(sFmtDescription, nCheckPos, nType, nNewKey, eLang);
801 
802     // set the new key
803     ImplSetFormatKey(nNewKey);
804     FormatChanged(FCT_PRECISION);
805 }
806 
807 //------------------------------------------------------------------------------
808 void FormattedField::FormatChanged( FORMAT_CHANGE_TYPE _nWhat )
809 {
810     DBG_CHKTHIS(FormattedField, NULL);
811     m_pLastOutputColor = NULL;
812 
813     if ( ( 0 != ( _nWhat & FCT_FORMATTER ) ) && m_pFormatter )
814         m_pFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_INTL_FORMAT );
815         // 95845 - 03.04.2002 - fs@openoffice.org
816 
817     ReFormat();
818 }
819 
820 //------------------------------------------------------------------------------
821 void FormattedField::Commit()
822 {
823     // remember the old text
824     String sOld( GetText() );
825 
826     // do the reformat
827     ReFormat();
828 
829     // did the text change?
830     if ( GetText() != sOld )
831     {   // consider the field as modified
832         Modify();
833         // but we have the most recent value now
834         m_bValueDirty = sal_False;
835     }
836 }
837 
838 //------------------------------------------------------------------------------
839 void FormattedField::ReFormat()
840 {
841     if (!IsEmptyFieldEnabled() || GetText().Len())
842     {
843         if (TreatingAsNumber())
844         {
845             double dValue = GetValue();
846             if ( m_bEnableNaN && ::rtl::math::isNan( dValue ) )
847                 return;
848             ImplSetValue( dValue, sal_True );
849         }
850         else
851             SetTextFormatted(GetTextValue());
852     }
853 }
854 
855 //------------------------------------------------------------------------------
856 long FormattedField::Notify(NotifyEvent& rNEvt)
857 {
858     DBG_CHKTHIS(FormattedField, NULL);
859 
860     if ((rNEvt.GetType() == EVENT_KEYINPUT) && !IsReadOnly())
861     {
862         const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
863         sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
864         switch ( rKEvt.GetKeyCode().GetCode() )
865         {
866             case KEY_UP:
867             case KEY_DOWN:
868             case KEY_PAGEUP:
869             case KEY_PAGEDOWN:
870                 if (!nMod && ImplGetFormatter()->IsTextFormat(m_nFormatKey))
871                 {
872                     // the base class would translate this into calls to Up/Down/First/Last,
873                     // but we don't want this if we are text-formatted
874                     return 1;
875                 }
876         }
877     }
878 
879     if ((rNEvt.GetType() == EVENT_COMMAND) && !IsReadOnly())
880     {
881         const CommandEvent* pCommand = rNEvt.GetCommandEvent();
882         if (pCommand->GetCommand() == COMMAND_WHEEL)
883         {
884             const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
885             if ((pData->GetMode() == COMMAND_WHEEL_SCROLL) && ImplGetFormatter()->IsTextFormat(m_nFormatKey))
886             {
887                 // same as above : prevent the base class from doing Up/Down-calls
888                 // (normally I should put this test into the Up/Down methods itself, shouldn't I ?)
889                 // FS - 71553 - 19.01.00
890                 return 1;
891             }
892         }
893     }
894 
895     if (rNEvt.GetType() == EVENT_LOSEFOCUS)
896     {
897         // Sonderbehandlung fuer leere Texte
898         if (GetText().Len() == 0)
899         {
900             if (!IsEmptyFieldEnabled())
901             {
902                 if (TreatingAsNumber())
903                 {
904                     ImplSetValue(m_dCurrentValue, sal_True);
905                     Modify();
906                 }
907                 else
908                 {
909                     String sNew = GetTextValue();
910                     if (sNew.Len())
911                         SetTextFormatted(sNew);
912                     else
913                         SetTextFormatted(m_sDefaultText);
914                 }
915                 m_bValueDirty = sal_False;
916             }
917         }
918         else
919         {
920             Commit();
921         }
922     }
923 
924     return SpinField::Notify( rNEvt );
925 }
926 
927 //------------------------------------------------------------------------------
928 void FormattedField::SetMinValue(double dMin)
929 {
930     DBG_CHKTHIS(FormattedField, NULL);
931     DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMinValue : only to be used in numeric mode !");
932 
933     m_dMinValue = dMin;
934     m_bHasMin = sal_True;
935     // fuer die Ueberpruefung des aktuellen Wertes an der neuen Grenze -> ImplSetValue
936     ReFormat();
937 }
938 
939 //------------------------------------------------------------------------------
940 void FormattedField::SetMaxValue(double dMax)
941 {
942     DBG_CHKTHIS(FormattedField, NULL);
943     DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMaxValue : only to be used in numeric mode !");
944 
945     m_dMaxValue = dMax;
946     m_bHasMax = sal_True;
947     // fuer die Ueberpruefung des aktuellen Wertes an der neuen Grenze -> ImplSetValue
948     ReFormat();
949 }
950 
951 //------------------------------------------------------------------------------
952 void FormattedField::SetTextValue(const XubString& rText)
953 {
954     DBG_CHKTHIS(FormattedField, NULL);
955     SetText(rText);
956     ReFormat();
957 }
958 
959 //------------------------------------------------------------------------------
960 void FormattedField::EnableEmptyField(sal_Bool bEnable)
961 {
962     DBG_CHKTHIS(FormattedField, NULL);
963     if (bEnable == m_bEnableEmptyField)
964         return;
965 
966     m_bEnableEmptyField = bEnable;
967     if (!m_bEnableEmptyField && GetText().Len()==0)
968         ImplSetValue(m_dCurrentValue, sal_True);
969 }
970 
971 //------------------------------------------------------------------------------
972 void FormattedField::ImplSetValue(double dVal, sal_Bool bForce)
973 {
974     DBG_CHKTHIS(FormattedField, NULL);
975 
976     if (m_bHasMin && (dVal<m_dMinValue))
977         dVal = m_dMinValue;
978     if (m_bHasMax && (dVal>m_dMaxValue))
979         dVal = m_dMaxValue;
980     if (!bForce && (dVal == GetValue()))
981         return;
982 
983     DBG_ASSERT(ImplGetFormatter() != NULL, "FormattedField::ImplSetValue : can't set a value without a formatter !");
984 
985     m_bValueDirty = sal_False;
986     m_dCurrentValue = dVal;
987 
988     String sNewText;
989     if (ImplGetFormatter()->IsTextFormat(m_nFormatKey))
990     {
991         // zuerst die Zahl als String im Standard-Format
992         String sTemp;
993         ImplGetFormatter()->GetOutputString(dVal, 0, sTemp, &m_pLastOutputColor);
994         // dann den String entsprechend dem Text-Format
995         ImplGetFormatter()->GetOutputString(sTemp, m_nFormatKey, sNewText, &m_pLastOutputColor);
996     }
997     else
998     {
999         if( IsUsingInputStringForFormatting())
1000             ImplGetFormatter()->GetInputLineString(dVal, m_nFormatKey, sNewText);
1001         else
1002             ImplGetFormatter()->GetOutputString(dVal, m_nFormatKey, sNewText, &m_pLastOutputColor);
1003     }
1004 
1005     ImplSetTextImpl(sNewText, NULL);
1006     m_bValueDirty = sal_False;
1007     DBG_ASSERT(CheckText(sNewText), "FormattedField::ImplSetValue : formatted string doesn't match the criteria !");
1008 }
1009 
1010 //------------------------------------------------------------------------------
1011 sal_Bool FormattedField::ImplGetValue(double& dNewVal)
1012 {
1013     DBG_CHKTHIS(FormattedField, NULL);
1014 
1015     dNewVal = m_dCurrentValue;
1016     if (!m_bValueDirty)
1017         return sal_True;
1018 
1019     dNewVal = m_dDefaultValue;
1020     String sText(GetText());
1021     if (!sText.Len())
1022         return sal_True;
1023 
1024     DBG_ASSERT(ImplGetFormatter() != NULL, "FormattedField::ImplGetValue : can't give you a current value without a formatter !");
1025 
1026     sal_uInt32 nFormatKey = m_nFormatKey;   // IsNumberFormat veraendert den FormatKey ...
1027 
1028     if (ImplGetFormatter()->IsTextFormat(nFormatKey) && m_bTreatAsNumber)
1029         // damit wir in einem als Text formatierten Feld trotzdem eine Eingabe wie '1,1' erkennen ...
1030         nFormatKey = 0;
1031 
1032     // Sonderbehandlung fuer %-Formatierung
1033     if (ImplGetFormatter()->GetType(m_nFormatKey) == NUMBERFORMAT_PERCENT)
1034     {
1035         // the language of our format
1036         LanguageType eLanguage = m_pFormatter->GetEntry(m_nFormatKey)->GetLanguage();
1037         // the default number format for this language
1038         sal_uLong nStandardNumericFormat = m_pFormatter->GetStandardFormat(NUMBERFORMAT_NUMBER, eLanguage);
1039 
1040         sal_uInt32 nTempFormat = nStandardNumericFormat;
1041         double dTemp;
1042         if (m_pFormatter->IsNumberFormat(sText, nTempFormat, dTemp) &&
1043             NUMBERFORMAT_NUMBER == m_pFormatter->GetType(nTempFormat))
1044             // der String entspricht einer Number-Formatierung, hat also nur kein %
1045             // -> append it
1046             sText += '%';
1047         // (with this, a input of '3' becomes '3%', which then by the formatter is translated
1048         // into 0.03. Without this, the formatter would give us the double 3 for an input '3',
1049         // which equals 300 percent.
1050     }
1051     if (!ImplGetFormatter()->IsNumberFormat(sText, nFormatKey, dNewVal))
1052         return sal_False;
1053 
1054 
1055     if (m_bHasMin && (dNewVal<m_dMinValue))
1056         dNewVal = m_dMinValue;
1057     if (m_bHasMax && (dNewVal>m_dMaxValue))
1058         dNewVal = m_dMaxValue;
1059     return sal_True;
1060 }
1061 
1062 //------------------------------------------------------------------------------
1063 void FormattedField::SetValue(double dVal)
1064 {
1065     DBG_CHKTHIS(FormattedField, NULL);
1066     ImplSetValue(dVal, m_bValueDirty);
1067 }
1068 
1069 //------------------------------------------------------------------------------
1070 double FormattedField::GetValue()
1071 {
1072     DBG_CHKTHIS(FormattedField, NULL);
1073 
1074     if ( !ImplGetValue( m_dCurrentValue ) )
1075     {
1076         if ( m_bEnableNaN )
1077             ::rtl::math::setNan( &m_dCurrentValue );
1078         else
1079             m_dCurrentValue = m_dDefaultValue;
1080     }
1081 
1082     m_bValueDirty = sal_False;
1083     return m_dCurrentValue;
1084 }
1085 
1086 //------------------------------------------------------------------------------
1087 void FormattedField::Up()
1088 {
1089     DBG_CHKTHIS(FormattedField, NULL);
1090     SetValue(GetValue() + m_dSpinSize);
1091         // das setValue handelt Bereichsueberschreitungen (min/max) automatisch
1092     SetModifyFlag();
1093     Modify();
1094 
1095     SpinField::Up();
1096 }
1097 
1098 //------------------------------------------------------------------------------
1099 void FormattedField::Down()
1100 {
1101     DBG_CHKTHIS(FormattedField, NULL);
1102     SetValue(GetValue() - m_dSpinSize);
1103     SetModifyFlag();
1104     Modify();
1105 
1106     SpinField::Down();
1107 }
1108 
1109 //------------------------------------------------------------------------------
1110 void FormattedField::First()
1111 {
1112     DBG_CHKTHIS(FormattedField, NULL);
1113     if (m_bHasMin)
1114     {
1115         SetValue(m_dMinValue);
1116         SetModifyFlag();
1117         Modify();
1118     }
1119 
1120     SpinField::First();
1121 }
1122 
1123 //------------------------------------------------------------------------------
1124 void FormattedField::Last()
1125 {
1126     DBG_CHKTHIS(FormattedField, NULL);
1127     if (m_bHasMax)
1128     {
1129         SetValue(m_dMaxValue);
1130         SetModifyFlag();
1131         Modify();
1132     }
1133 
1134     SpinField::Last();
1135 }
1136 
1137 //------------------------------------------------------------------------------
1138 void FormattedField::UseInputStringForFormatting( bool bUseInputStr /* = true */ )
1139 {
1140     m_bUseInputStringForFormatting = bUseInputStr;
1141 }
1142 
1143 //------------------------------------------------------------------------------
1144 bool FormattedField::IsUsingInputStringForFormatting() const
1145 {
1146     return m_bUseInputStringForFormatting;
1147 }
1148 
1149 
1150 //==============================================================================
1151 //------------------------------------------------------------------------------
1152 DoubleNumericField::~DoubleNumericField()
1153 {
1154 #ifdef REGEXP_SUPPORT
1155     delete m_pConformanceTester;
1156 #else
1157     delete m_pNumberValidator;
1158 #endif
1159 }
1160 
1161 //------------------------------------------------------------------------------
1162 void DoubleNumericField::FormatChanged(FORMAT_CHANGE_TYPE nWhat)
1163 {
1164     ResetConformanceTester();
1165     FormattedField::FormatChanged(nWhat);
1166 }
1167 
1168 //------------------------------------------------------------------------------
1169 sal_Bool DoubleNumericField::CheckText(const XubString& sText) const
1170 {
1171     // We'd like to implement this using the NumberFormatter::IsNumberFormat, but unfortunately, this doesn't
1172     // recognize fragments of numbers (like, for instance "1e", which happens during entering e.g. "1e10")
1173     // Thus, the roundabout way via a regular expression
1174 
1175 #ifdef REGEXP_SUPPORT
1176     if (!sText.Len())
1177         return sal_True;
1178 
1179     String sForceComplete = '_';
1180     sForceComplete += sText;
1181     sForceComplete += '_';
1182 
1183     sal_uInt16 nStart = 0, nEnd = sForceComplete.Len();
1184     sal_Bool bFound = m_pConformanceTester->SearchFrwrd(sForceComplete, &nStart, &nEnd);
1185 
1186     if (bFound && (nStart == 0) && (nEnd == sForceComplete.Len()))
1187         return sal_True;
1188 
1189     return sal_False;
1190 #else
1191     return m_pNumberValidator->isValidNumericFragment( sText );
1192 #endif
1193 }
1194 
1195 //------------------------------------------------------------------------------
1196 void DoubleNumericField::ResetConformanceTester()
1197 {
1198     // the thousands and the decimal separator are language dependent
1199     const SvNumberformat* pFormatEntry = ImplGetFormatter()->GetEntry(m_nFormatKey);
1200 
1201     sal_Unicode cSeparatorThousand = ',';
1202     sal_Unicode cSeparatorDecimal = '.';
1203     if (pFormatEntry)
1204     {
1205         Locale aLocale;
1206         MsLangId::convertLanguageToLocale( pFormatEntry->GetLanguage(), aLocale );
1207         LocaleDataWrapper aLocaleInfo(::comphelper::getProcessServiceFactory(), aLocale);
1208 
1209         String sSeparator = aLocaleInfo.getNumThousandSep();
1210         if (sSeparator.Len())
1211             cSeparatorThousand = sSeparator.GetBuffer()[0];
1212 
1213         sSeparator = aLocaleInfo.getNumDecimalSep();
1214         if (sSeparator.Len())
1215             cSeparatorDecimal = sSeparator.GetBuffer()[0];
1216     }
1217 
1218 #ifdef REGEXP_SUPPORT
1219     String sDescription = String::CreateFromAscii(szNumericInput);
1220 
1221     String sReplaceWith((sal_Unicode)'\\');
1222     sReplaceWith += cSeparatorThousand;
1223     sDescription.SearchAndReplaceAscii("\\,", sReplaceWith);
1224 
1225     sReplaceWith = (sal_Unicode)'\\';
1226     sReplaceWith += cSeparatorDecimal;
1227     sDescription.SearchAndReplaceAscii("\\.", sReplaceWith);
1228 
1229     delete m_pConformanceTester;
1230 
1231     SearchOptions aParam;
1232     aParam.algorithmType = SearchAlgorithms_REGEXP;
1233     aParam.searchFlag = SearchFlags::ALL_IGNORE_CASE;
1234     aParam.searchString = sDescription;
1235     aParam.transliterateFlags = 0;
1236 
1237     String sLanguage, sCountry;
1238     ConvertLanguageToIsoNames( pFormatEntry ? pFormatEntry->GetLanguage() : LANGUAGE_ENGLISH_US, sLanguage, sCountry );
1239     aParam.Locale.Language = sLanguage;
1240     aParam.Locale.Country = sCountry;
1241 
1242     m_pConformanceTester = new ::utl::TextSearch(aParam);
1243 #else
1244     delete m_pNumberValidator;
1245     m_pNumberValidator = new validation::NumberValidator( cSeparatorThousand, cSeparatorDecimal );
1246 #endif
1247 }
1248 
1249 
1250 //==============================================================================
1251 
1252 //------------------------------------------------------------------------------
1253 DoubleCurrencyField::DoubleCurrencyField(Window* pParent, WinBits nStyle)
1254     :FormattedField(pParent, nStyle)
1255     ,m_bChangingFormat(sal_False)
1256 {
1257     m_bPrependCurrSym = sal_False;
1258 
1259     // initialize with a system currency format
1260     m_sCurrencySymbol = SvtSysLocale().GetLocaleData().getCurrSymbol();
1261     UpdateCurrencyFormat();
1262 }
1263 
1264 //------------------------------------------------------------------------------
1265 DoubleCurrencyField::DoubleCurrencyField(Window* pParent, const ResId& rResId)
1266     :FormattedField(pParent, rResId)
1267     ,m_bChangingFormat(sal_False)
1268 {
1269     m_bPrependCurrSym = sal_False;
1270 
1271     // initialize with a system currency format
1272     m_sCurrencySymbol = SvtSysLocale().GetLocaleData().getCurrSymbol();
1273     UpdateCurrencyFormat();
1274 }
1275 
1276 //------------------------------------------------------------------------------
1277 void DoubleCurrencyField::FormatChanged(FORMAT_CHANGE_TYPE nWhat)
1278 {
1279     if (m_bChangingFormat)
1280     {
1281         FormattedField::FormatChanged(nWhat);
1282         return;
1283     }
1284 
1285     switch (nWhat)
1286     {
1287         case FCT_FORMATTER:
1288         case FCT_PRECISION:
1289         case FCT_THOUSANDSSEP:
1290             // the aspects which changed don't take our currency settings into account (in fact, they most probably
1291             // destroyed them)
1292             UpdateCurrencyFormat();
1293             break;
1294         case FCT_KEYONLY:
1295             DBG_ERROR("DoubleCurrencyField::FormatChanged : somebody modified my key !");
1296             // We always build our own format from the settings we get via special methods (setCurrencySymbol etc.).
1297             // Nobody but ourself should modifiy the format key directly !
1298             break;
1299     }
1300 
1301     FormattedField::FormatChanged(nWhat);
1302 }
1303 
1304 //------------------------------------------------------------------------------
1305 void DoubleCurrencyField::setCurrencySymbol(const String& _sSymbol)
1306 {
1307     if (m_sCurrencySymbol == _sSymbol)
1308         return;
1309 
1310     m_sCurrencySymbol  = _sSymbol;
1311     UpdateCurrencyFormat();
1312     FormatChanged(FCT_CURRENCY_SYMBOL);
1313 }
1314 
1315 //------------------------------------------------------------------------------
1316 void DoubleCurrencyField::setPrependCurrSym(sal_Bool _bPrepend)
1317 {
1318     if (m_bPrependCurrSym == _bPrepend)
1319          return;
1320 
1321     m_bPrependCurrSym = _bPrepend;
1322     UpdateCurrencyFormat();
1323     FormatChanged(FCT_CURRSYM_POSITION);
1324 }
1325 
1326 //------------------------------------------------------------------------------
1327 void DoubleCurrencyField::UpdateCurrencyFormat()
1328 {
1329     // the old settings
1330     XubString sOldFormat;
1331     LanguageType eLanguage;
1332     GetFormat(sOldFormat, eLanguage);
1333     sal_Bool bThSep = GetThousandsSep();
1334     sal_uInt16 nDigits = GetDecimalDigits();
1335 
1336     // build a new format string with the base class' and my own settings
1337     Locale aLocale;
1338     MsLangId::convertLanguageToLocale( eLanguage, aLocale );
1339     LocaleDataWrapper aLocaleInfo(::comphelper::getProcessServiceFactory(), aLocale);
1340 
1341     XubString sNewFormat;
1342     if (bThSep)
1343     {
1344         sNewFormat = '#';
1345         sNewFormat += aLocaleInfo.getNumThousandSep();
1346         sNewFormat.AppendAscii("##0");
1347     }
1348     else
1349         sNewFormat = '0';
1350 
1351     if (nDigits)
1352     {
1353         sNewFormat += aLocaleInfo.getNumDecimalSep();
1354 
1355         XubString sTemp;
1356         sTemp.Fill(nDigits, '0');
1357         sNewFormat += sTemp;
1358     }
1359 
1360     if (getPrependCurrSym())
1361     {
1362         XubString sSymbol = getCurrencySymbol();
1363         sSymbol.EraseLeadingChars(' ');
1364         sSymbol.EraseTrailingChars(' ');
1365 
1366         XubString sTemp = String::CreateFromAscii("[$");
1367         sTemp += sSymbol;
1368         sTemp.AppendAscii("] ");
1369         sTemp += sNewFormat;
1370 
1371         // for negative values : $ -0.00, not -$ 0.00 ...
1372         // (the real solution would be a possibility to choose a "positive currency format" and a "negative currency format" ...
1373         // But not now ... (and hey, you could take a formatted field for this ....))
1374         // FS - 31.03.00 74642
1375         sTemp.AppendAscii(";[$");
1376         sTemp += sSymbol;
1377         sTemp.AppendAscii("] -");
1378         sTemp += sNewFormat;
1379 
1380         sNewFormat = sTemp;
1381     }
1382     else
1383     {
1384         XubString sTemp = getCurrencySymbol();
1385         sTemp.EraseLeadingChars(' ');
1386         sTemp.EraseTrailingChars(' ');
1387 
1388         sNewFormat += String::CreateFromAscii(" [$");
1389         sNewFormat += sTemp;
1390         sNewFormat += ']';
1391     }
1392 
1393     // set this new basic format
1394     m_bChangingFormat = sal_True;
1395     SetFormat(sNewFormat, eLanguage);
1396     m_bChangingFormat = sal_False;
1397 }
1398 
1399