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