xref: /trunk/main/svtools/source/control/fmtfield.cxx (revision cdf0e10c)
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