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