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 : #include <tools/debug.hxx>
21 : #include <comphelper/processfactory.hxx>
22 : #include <comphelper/string.hxx>
23 : #include <unotools/localedatawrapper.hxx>
24 : #include <vcl/svapp.hxx>
25 : #include <vcl/builderfactory.hxx>
26 : #include <vcl/settings.hxx>
27 : #include <svl/zformat.hxx>
28 : #include <svtools/fmtfield.hxx>
29 : #include <i18nlangtag/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 74 : 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 : bool isValidNumericFragment( const OUString& _rText );
85 :
86 : private:
87 : bool implValidateNormalized( const OUString& _rText );
88 : };
89 :
90 296 : static void lcl_insertStopTransition( StateTransitions& _rRow )
91 : {
92 296 : _rRow.insert( Transition( '_', END ) );
93 296 : }
94 :
95 222 : static void lcl_insertStartExponentTransition( StateTransitions& _rRow )
96 : {
97 222 : _rRow.insert( Transition( 'e', EXPONENT_START ) );
98 222 : }
99 :
100 148 : static void lcl_insertSignTransitions( StateTransitions& _rRow, const State eNextState )
101 : {
102 148 : _rRow.insert( Transition( '-', eNextState ) );
103 148 : _rRow.insert( Transition( '+', eNextState ) );
104 148 : }
105 :
106 370 : static void lcl_insertDigitTransitions( StateTransitions& _rRow, const State eNextState )
107 : {
108 4070 : for ( sal_Unicode aChar = '0'; aChar <= '9'; ++aChar )
109 3700 : _rRow.insert( Transition( aChar, eNextState ) );
110 370 : }
111 :
112 148 : static void lcl_insertCommonPreCommaTransitions( StateTransitions& _rRow, const sal_Unicode _cThSep, const sal_Unicode _cDecSep )
113 : {
114 : // digits are allowed
115 148 : lcl_insertDigitTransitions( _rRow, DIGIT_PRE_COMMA );
116 :
117 : // the thousand separator is allowed
118 148 : _rRow.insert( Transition( _cThSep, DIGIT_PRE_COMMA ) );
119 :
120 : // a comma is allowed
121 148 : _rRow.insert( Transition( _cDecSep, DIGIT_POST_COMMA ) );
122 148 : }
123 :
124 74 : NumberValidator::NumberValidator( const sal_Unicode _cThSep, const sal_Unicode _cDecSep )
125 : :m_cThSep( _cThSep )
126 74 : ,m_cDecSep( _cDecSep )
127 : {
128 : // build up our transition table
129 :
130 : // how to proceed from START
131 : {
132 74 : StateTransitions& rRow = m_aTransitions[ START ];
133 74 : rRow.insert( Transition( '_', NUM_START ) );
134 : // if we encounter the normalizing character, we want to proceed with the number
135 : }
136 :
137 : // how to proceed from NUM_START
138 : {
139 74 : StateTransitions& rRow = m_aTransitions[ NUM_START ];
140 :
141 : // a sign is allowed
142 74 : lcl_insertSignTransitions( rRow, DIGIT_PRE_COMMA );
143 :
144 : // common transitions for the two pre-comma states
145 74 : lcl_insertCommonPreCommaTransitions( rRow, m_cThSep, m_cDecSep );
146 :
147 : // the exponent may start here
148 : // (this would mean string like "_+e10_", but this is a valid fragment, though no valid number)
149 74 : lcl_insertStartExponentTransition( rRow );
150 : }
151 :
152 : // how to proceed from DIGIT_PRE_COMMA
153 : {
154 74 : StateTransitions& rRow = m_aTransitions[ DIGIT_PRE_COMMA ];
155 :
156 : // common transitions for the two pre-comma states
157 74 : lcl_insertCommonPreCommaTransitions( rRow, m_cThSep, m_cDecSep );
158 :
159 : // the exponent may start here
160 74 : lcl_insertStartExponentTransition( rRow );
161 :
162 : // the final transition indicating the end of the string
163 : // (if there is no comma and no post-comma, then the string may end here)
164 74 : lcl_insertStopTransition( rRow );
165 : }
166 :
167 : // how to proceed from DIGIT_POST_COMMA
168 : {
169 74 : StateTransitions& rRow = m_aTransitions[ DIGIT_POST_COMMA ];
170 :
171 : // there might be digits, which would keep the state at DIGIT_POST_COMMA
172 74 : lcl_insertDigitTransitions( rRow, DIGIT_POST_COMMA );
173 :
174 : // the exponent may start here
175 74 : lcl_insertStartExponentTransition( rRow );
176 :
177 : // the string may end here
178 74 : lcl_insertStopTransition( rRow );
179 : }
180 :
181 : // how to proceed from EXPONENT_START
182 : {
183 74 : StateTransitions& rRow = m_aTransitions[ EXPONENT_START ];
184 :
185 : // there may be a sign
186 74 : lcl_insertSignTransitions( rRow, EXPONENT_DIGIT );
187 :
188 : // there may be digits
189 74 : lcl_insertDigitTransitions( rRow, EXPONENT_DIGIT );
190 :
191 : // the string may end here
192 74 : lcl_insertStopTransition( rRow );
193 : }
194 :
195 : // how to proceed from EXPONENT_DIGIT
196 : {
197 74 : StateTransitions& rRow = m_aTransitions[ EXPONENT_DIGIT ];
198 :
199 : // there may be digits
200 74 : lcl_insertDigitTransitions( rRow, EXPONENT_DIGIT );
201 :
202 : // the string may end here
203 74 : lcl_insertStopTransition( rRow );
204 : }
205 :
206 : // how to proceed from END
207 : {
208 74 : /*StateTransitions& rRow =*/ m_aTransitions[ EXPONENT_DIGIT ];
209 : // no valid transition to leave this state
210 : // (note that we, for consistency, nevertheless want to have a row in the table)
211 : }
212 74 : }
213 :
214 28 : bool NumberValidator::implValidateNormalized( const OUString& _rText )
215 : {
216 28 : const sal_Unicode* pCheckPos = _rText.getStr();
217 28 : State eCurrentState = START;
218 :
219 212 : while ( END != eCurrentState )
220 : {
221 : // look up the transition row for the current state
222 164 : TransitionTable::const_iterator aRow = m_aTransitions.find( eCurrentState );
223 : DBG_ASSERT( m_aTransitions.end() != aRow,
224 : "NumberValidator::implValidateNormalized: invalid transition table (row not found)!" );
225 :
226 164 : if ( m_aTransitions.end() != aRow )
227 : {
228 : // look up the current character in this row
229 164 : StateTransitions::const_iterator aTransition = aRow->second.find( *pCheckPos );
230 164 : if ( aRow->second.end() != aTransition )
231 : {
232 : // there is a valid transition for this character
233 156 : eCurrentState = aTransition->second;
234 156 : ++pCheckPos;
235 156 : continue;
236 : }
237 : }
238 :
239 : // if we're here, there is no valid transition
240 8 : break;
241 : }
242 :
243 : DBG_ASSERT( ( END != eCurrentState ) || ( 0 == *pCheckPos ),
244 : "NumberValidator::implValidateNormalized: inconsistency!" );
245 : // if we're at END, then the string should be done, too - the string should be normalized, means ending
246 : // a "_" and not containing any other "_" (except at the start), and "_" is the only possibility
247 : // to reach the END state
248 :
249 : // the string is valid if and only if we reached the final state
250 28 : return ( END == eCurrentState );
251 : }
252 :
253 28 : bool NumberValidator::isValidNumericFragment( const OUString& _rText )
254 : {
255 28 : if ( _rText.isEmpty() )
256 : // empty strings are always allowed
257 0 : return true;
258 :
259 : // normalize the string
260 28 : OUString sNormalized( "_" );
261 28 : sNormalized += _rText;
262 28 : sNormalized += "_";
263 :
264 28 : return implValidateNormalized( sNormalized );
265 : }
266 : }
267 :
268 : SvNumberFormatter* FormattedField::StaticFormatter::s_cFormatter = NULL;
269 : sal_uLong FormattedField::StaticFormatter::s_nReferences = 0;
270 :
271 35 : SvNumberFormatter* FormattedField::StaticFormatter::GetFormatter()
272 : {
273 35 : if (!s_cFormatter)
274 : {
275 : // get the Office's locale and translate
276 35 : LanguageType eSysLanguage = SvtSysLocale().GetLanguageTag().getLanguageType( false);
277 : s_cFormatter = new SvNumberFormatter(
278 : ::comphelper::getProcessComponentContext(),
279 35 : eSysLanguage);
280 : }
281 35 : return s_cFormatter;
282 : }
283 :
284 63 : FormattedField::StaticFormatter::StaticFormatter()
285 : {
286 63 : ++s_nReferences;
287 63 : }
288 :
289 63 : FormattedField::StaticFormatter::~StaticFormatter()
290 : {
291 63 : if (--s_nReferences == 0)
292 : {
293 36 : delete s_cFormatter;
294 36 : s_cFormatter = NULL;
295 : }
296 63 : }
297 :
298 :
299 63 : FormattedField::FormattedField(vcl::Window* pParent, WinBits nStyle, SvNumberFormatter* pInitialFormatter, sal_Int32 nFormatKey)
300 : :SpinField(pParent, nStyle)
301 : ,m_aLastSelection(0,0)
302 : ,m_dMinValue(0)
303 : ,m_dMaxValue(0)
304 : ,m_bHasMin(false)
305 : ,m_bHasMax(false)
306 : ,m_bStrictFormat(true)
307 : ,m_bValueDirty(true)
308 : ,m_bEnableEmptyField(true)
309 : ,m_bAutoColor(false)
310 : ,m_bEnableNaN(false)
311 : ,m_dCurrentValue(0)
312 : ,m_dDefaultValue(0)
313 : ,m_nFormatKey(0)
314 : ,m_pFormatter(NULL)
315 : ,m_dSpinSize(1)
316 : ,m_dSpinFirst(-1000000)
317 : ,m_dSpinLast(1000000)
318 : ,m_bTreatAsNumber(true)
319 : ,m_pLastOutputColor(NULL)
320 63 : ,m_bUseInputStringForFormatting(false)
321 : {
322 :
323 63 : if (pInitialFormatter)
324 : {
325 0 : m_pFormatter = pInitialFormatter;
326 0 : m_nFormatKey = nFormatKey;
327 : }
328 63 : }
329 :
330 0 : VCL_BUILDER_FACTORY_ARGS(FormattedField, WB_BORDER | WB_SPIN)
331 :
332 78 : void FormattedField::SetText(const OUString& rStr)
333 : {
334 :
335 78 : SpinField::SetText(rStr);
336 78 : m_bValueDirty = true;
337 78 : }
338 :
339 0 : void FormattedField::SetText( const OUString& rStr, const Selection& rNewSelection )
340 : {
341 :
342 0 : SpinField::SetText( rStr, rNewSelection );
343 0 : m_bValueDirty = true;
344 0 : }
345 :
346 36 : void FormattedField::SetTextFormatted(const OUString& rStr)
347 : {
348 :
349 : #if defined DBG_UTIL
350 : if (ImplGetFormatter()->IsTextFormat(m_nFormatKey))
351 : DBG_WARNING("FormattedField::SetTextFormatted : valid only with text formats !");
352 : #endif
353 :
354 36 : m_sCurrentTextValue = rStr;
355 :
356 36 : OUString sFormatted;
357 36 : double dNumber = 0.0;
358 : // IsNumberFormat changes the format key parameter
359 36 : sal_uInt32 nTempFormatKey = static_cast< sal_uInt32 >( m_nFormatKey );
360 36 : if( IsUsingInputStringForFormatting() &&
361 0 : ImplGetFormatter()->IsNumberFormat(m_sCurrentTextValue, nTempFormatKey, dNumber) )
362 : {
363 0 : ImplGetFormatter()->GetInputLineString(dNumber, m_nFormatKey, sFormatted);
364 : }
365 : else
366 : {
367 : ImplGetFormatter()->GetOutputString(m_sCurrentTextValue,
368 : m_nFormatKey,
369 : sFormatted,
370 36 : &m_pLastOutputColor);
371 : }
372 :
373 : // calculate the new selection
374 36 : Selection aSel(GetSelection());
375 36 : Selection aNewSel(aSel);
376 36 : aNewSel.Justify();
377 36 : sal_Int32 nNewLen = sFormatted.getLength();
378 36 : sal_Int32 nCurrentLen = GetText().getLength();
379 36 : if ((nNewLen > nCurrentLen) && (aNewSel.Max() == nCurrentLen))
380 : { // the new text is longer and the cursor was behind the last char (of the old text)
381 7 : if (aNewSel.Min() == 0)
382 : { // the whole text was selected -> select the new text on the whole, too
383 7 : aNewSel.Max() = nNewLen;
384 7 : if (!nCurrentLen)
385 : { // there wasn't really a previous selection (as there was no previous text), we're setting a new one -> check the selection options
386 7 : SelectionOptions nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
387 7 : if (nSelOptions & SelectionOptions::ShowFirst)
388 : { // selection should be from right to left -> swap min and max
389 5 : aNewSel.Min() = aNewSel.Max();
390 5 : aNewSel.Max() = 0;
391 : }
392 : }
393 : }
394 0 : else if (aNewSel.Max() == aNewSel.Min())
395 : { // there was no selection -> set the cursor behind the new last char
396 0 : aNewSel.Max() = nNewLen;
397 0 : aNewSel.Min() = nNewLen;
398 : }
399 : }
400 29 : else if (aNewSel.Max() > nNewLen)
401 0 : aNewSel.Max() = nNewLen;
402 : else
403 29 : aNewSel = aSel; // don't use the justified version
404 36 : SpinField::SetText(sFormatted, aNewSel);
405 36 : m_bValueDirty = false;
406 36 : }
407 :
408 1 : OUString FormattedField::GetTextValue() const
409 : {
410 1 : if (m_bValueDirty)
411 : {
412 0 : const_cast<FormattedField*>(this)->m_sCurrentTextValue = GetText();
413 0 : const_cast<FormattedField*>(this)->m_bValueDirty = false;
414 : }
415 1 : return m_sCurrentTextValue;
416 : }
417 :
418 53 : void FormattedField::EnableNotANumber( bool _bEnable )
419 : {
420 53 : if ( m_bEnableNaN == _bEnable )
421 80 : return;
422 :
423 26 : m_bEnableNaN = _bEnable;
424 : }
425 :
426 70 : void FormattedField::SetAutoColor(bool _bAutomatic)
427 : {
428 70 : if (_bAutomatic == m_bAutoColor)
429 105 : return;
430 :
431 35 : m_bAutoColor = _bAutomatic;
432 35 : if (m_bAutoColor)
433 : { // if auto color is switched on, adjust the current text color, too
434 35 : if (m_pLastOutputColor)
435 0 : SetControlForeground(*m_pLastOutputColor);
436 : else
437 35 : SetControlForeground();
438 : }
439 : }
440 :
441 69 : void FormattedField::impl_Modify(bool makeValueDirty)
442 : {
443 :
444 69 : if (!IsStrictFormat())
445 : {
446 0 : if(makeValueDirty)
447 0 : m_bValueDirty = true;
448 0 : SpinField::Modify();
449 69 : return;
450 : }
451 :
452 69 : OUString sCheck = GetText();
453 69 : if (CheckText(sCheck))
454 : {
455 61 : m_sLastValidText = sCheck;
456 61 : m_aLastSelection = GetSelection();
457 61 : if(makeValueDirty)
458 61 : m_bValueDirty = true;
459 : }
460 : else
461 : {
462 8 : ImplSetTextImpl(m_sLastValidText, &m_aLastSelection);
463 : }
464 :
465 69 : SpinField::Modify();
466 : }
467 :
468 69 : void FormattedField::Modify()
469 : {
470 :
471 69 : impl_Modify();
472 69 : }
473 :
474 90 : void FormattedField::ImplSetTextImpl(const OUString& rNew, Selection* pNewSel)
475 : {
476 :
477 90 : if (m_bAutoColor)
478 : {
479 81 : if (m_pLastOutputColor)
480 0 : SetControlForeground(*m_pLastOutputColor);
481 : else
482 81 : SetControlForeground();
483 : }
484 :
485 90 : if (pNewSel)
486 8 : SpinField::SetText(rNew, *pNewSel);
487 : else
488 : {
489 82 : Selection aSel(GetSelection());
490 82 : aSel.Justify();
491 :
492 82 : sal_Int32 nNewLen = rNew.getLength();
493 82 : sal_Int32 nCurrentLen = GetText().getLength();
494 :
495 82 : if ((nNewLen > nCurrentLen) && (aSel.Max() == nCurrentLen))
496 : { // new new text is longer and the cursor is behind the last char
497 34 : if (aSel.Min() == 0)
498 : { // the whole text was selected -> select the new text on the whole, too
499 32 : aSel.Max() = nNewLen;
500 32 : if (!nCurrentLen)
501 : { // there wasn't really a previous selection (as there was no previous text), we're setting a new one -> check the selection options
502 20 : SelectionOptions nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
503 20 : if (nSelOptions & SelectionOptions::ShowFirst)
504 : { // selection should be from right to left -> swap min and max
505 9 : aSel.Min() = aSel.Max();
506 9 : aSel.Max() = 0;
507 : }
508 : }
509 : }
510 2 : else if (aSel.Max() == aSel.Min())
511 : { // there was no selection -> set the cursor behind the new last char
512 0 : aSel.Max() = nNewLen;
513 0 : aSel.Min() = nNewLen;
514 : }
515 : }
516 48 : else if (aSel.Max() > nNewLen)
517 4 : aSel.Max() = nNewLen;
518 82 : SpinField::SetText(rNew, aSel);
519 : }
520 :
521 90 : m_bValueDirty = true; // not always necessary, but better re-evaluate for safety reasons
522 90 : }
523 :
524 0 : bool FormattedField::PreNotify(NotifyEvent& rNEvt)
525 : {
526 0 : if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
527 0 : m_aLastSelection = GetSelection();
528 0 : return SpinField::PreNotify(rNEvt);
529 : }
530 :
531 203 : void FormattedField::ImplSetFormatKey(sal_uLong nFormatKey)
532 : {
533 :
534 203 : m_nFormatKey = nFormatKey;
535 203 : bool bNeedFormatter = (m_pFormatter == NULL) && (nFormatKey != 0);
536 203 : if (bNeedFormatter)
537 : {
538 0 : ImplGetFormatter(); // this creates a standard formatter
539 :
540 : // It might happen that the standard formatter makes no sense here, but it takes a default
541 : // format. Thus, it is possible to set one of the other standard keys (which are spanning
542 : // across multiple formatters).
543 0 : m_nFormatKey = nFormatKey;
544 : // When calling SetFormatKey without a formatter, the key must be one of the standard values
545 : // that is available for all formatters (and, thus, also in this new one).
546 : DBG_ASSERT(m_pFormatter->GetEntry(nFormatKey) != NULL, "FormattedField::ImplSetFormatKey : invalid format key !");
547 : }
548 203 : }
549 :
550 123 : void FormattedField::SetFormatKey(sal_uLong nFormatKey)
551 : {
552 123 : bool bNoFormatter = (m_pFormatter == NULL);
553 123 : ImplSetFormatKey(nFormatKey);
554 123 : FormatChanged((bNoFormatter && (m_pFormatter != NULL)) ? FORMAT_CHANGE_TYPE::FORMATTER : FORMAT_CHANGE_TYPE::KEYONLY);
555 123 : }
556 :
557 64 : void FormattedField::SetFormatter(SvNumberFormatter* pFormatter, bool bResetFormat)
558 : {
559 :
560 64 : if (bResetFormat)
561 : {
562 63 : m_pFormatter = pFormatter;
563 :
564 : // calc the default format key from the Office's UI locale
565 63 : if ( m_pFormatter )
566 : {
567 : // get the Office's locale and translate
568 63 : LanguageType eSysLanguage = SvtSysLocale().GetLanguageTag().getLanguageType( false);
569 : // get the standard numeric format for this language
570 63 : m_nFormatKey = m_pFormatter->GetStandardFormat( css::util::NumberFormat::NUMBER, eSysLanguage );
571 : }
572 : else
573 0 : m_nFormatKey = 0;
574 : }
575 : else
576 : {
577 : LanguageType aOldLang;
578 1 : OUString sOldFormat = GetFormat(aOldLang);
579 :
580 1 : sal_uInt32 nDestKey = pFormatter->TestNewString(sOldFormat);
581 1 : if (nDestKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
582 : {
583 : // language of the new formatter
584 0 : const SvNumberformat* pDefaultEntry = pFormatter->GetEntry(0);
585 0 : LanguageType aNewLang = pDefaultEntry ? pDefaultEntry->GetLanguage() : LANGUAGE_DONTKNOW;
586 :
587 : // convert the old format string into the new language
588 : sal_Int32 nCheckPos;
589 : short nType;
590 0 : pFormatter->PutandConvertEntry(sOldFormat, nCheckPos, nType, nDestKey, aOldLang, aNewLang);
591 0 : m_nFormatKey = nDestKey;
592 : }
593 1 : m_pFormatter = pFormatter;
594 : }
595 :
596 64 : FormatChanged(FORMAT_CHANGE_TYPE::FORMATTER);
597 64 : }
598 :
599 192 : OUString FormattedField::GetFormat(LanguageType& eLang) const
600 : {
601 192 : const SvNumberformat* pFormatEntry = ImplGetFormatter()->GetEntry(m_nFormatKey);
602 : DBG_ASSERT(pFormatEntry != NULL, "FormattedField::GetFormat: no number format for the given format key.");
603 192 : OUString sFormatString = pFormatEntry ? pFormatEntry->GetFormatstring() : OUString();
604 192 : eLang = pFormatEntry ? pFormatEntry->GetLanguage() : LANGUAGE_DONTKNOW;
605 :
606 192 : return sFormatString;
607 : }
608 :
609 111 : bool FormattedField::SetFormat(const OUString& rFormatString, LanguageType eLang)
610 : {
611 111 : sal_uInt32 nNewKey = ImplGetFormatter()->TestNewString(rFormatString, eLang);
612 111 : if (nNewKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
613 : {
614 : sal_Int32 nCheckPos;
615 : short nType;
616 94 : OUString rFormat(rFormatString);
617 94 : if (!ImplGetFormatter()->PutEntry(rFormat, nCheckPos, nType, nNewKey, eLang))
618 0 : return false;
619 94 : DBG_ASSERT(nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND, "FormattedField::SetFormatString : PutEntry returned an invalid key !");
620 : }
621 :
622 111 : if (nNewKey != m_nFormatKey)
623 94 : SetFormatKey(nNewKey);
624 111 : return true;
625 : }
626 :
627 111 : bool FormattedField::GetThousandsSep() const
628 : {
629 : DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
630 : "FormattedField::GetThousandsSep : Are you sure what you are doing when setting the precision of a text format?");
631 :
632 : bool bThousand, IsRed;
633 : sal_uInt16 nPrecision, nAnzLeading;
634 111 : ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading);
635 :
636 111 : return bThousand;
637 : }
638 :
639 50 : void FormattedField::SetThousandsSep(bool _bUseSeparator)
640 : {
641 : DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
642 : "FormattedField::SetThousandsSep : Are you sure what you are doing when setting the precision of a text format?");
643 :
644 : // get the current settings
645 : bool bThousand, IsRed;
646 : sal_uInt16 nPrecision, nAnzLeading;
647 50 : ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading);
648 50 : if (bThousand == (bool)_bUseSeparator)
649 74 : return;
650 :
651 : // we need the language for the following
652 : LanguageType eLang;
653 26 : GetFormat(eLang);
654 :
655 : // generate a new format ...
656 26 : OUString sFmtDescription = ImplGetFormatter()->GenerateFormat(m_nFormatKey, eLang, _bUseSeparator, IsRed, nPrecision, nAnzLeading);
657 : // ... and introduce it to the formatter
658 26 : sal_Int32 nCheckPos = 0;
659 : sal_uInt32 nNewKey;
660 : short nType;
661 26 : ImplGetFormatter()->PutEntry(sFmtDescription, nCheckPos, nType, nNewKey, eLang);
662 :
663 : // set the new key
664 26 : ImplSetFormatKey(nNewKey);
665 26 : FormatChanged(FORMAT_CHANGE_TYPE::THOUSANDSSEP);
666 : }
667 :
668 111 : sal_uInt16 FormattedField::GetDecimalDigits() const
669 : {
670 : DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
671 : "FormattedField::GetDecimalDigits : Are you sure what you are doing when setting the precision of a text format?");
672 :
673 : bool bThousand, IsRed;
674 : sal_uInt16 nPrecision, nAnzLeading;
675 111 : ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading);
676 :
677 111 : return nPrecision;
678 : }
679 :
680 54 : void FormattedField::SetDecimalDigits(sal_uInt16 _nPrecision)
681 : {
682 : DBG_ASSERT(!ImplGetFormatter()->IsTextFormat(m_nFormatKey),
683 : "FormattedField::SetDecimalDigits : Are you sure what you are doing when setting the precision of a text format?");
684 :
685 : // get the current settings
686 : bool bThousand, IsRed;
687 : sal_uInt16 nPrecision, nAnzLeading;
688 54 : ImplGetFormatter()->GetFormatSpecialInfo(m_nFormatKey, bThousand, IsRed, nPrecision, nAnzLeading);
689 54 : if (nPrecision == _nPrecision)
690 54 : return;
691 :
692 : // we need the language for the following
693 : LanguageType eLang;
694 54 : GetFormat(eLang);
695 :
696 : // generate a new format ...
697 54 : OUString sFmtDescription = ImplGetFormatter()->GenerateFormat(m_nFormatKey, eLang, bThousand, IsRed, _nPrecision, nAnzLeading);
698 : // ... and introduce it to the formatter
699 54 : sal_Int32 nCheckPos = 0;
700 : sal_uInt32 nNewKey;
701 : short nType;
702 54 : ImplGetFormatter()->PutEntry(sFmtDescription, nCheckPos, nType, nNewKey, eLang);
703 :
704 : // set the new key
705 54 : ImplSetFormatKey(nNewKey);
706 54 : FormatChanged(FORMAT_CHANGE_TYPE::PRECISION);
707 : }
708 :
709 304 : void FormattedField::FormatChanged( FORMAT_CHANGE_TYPE _nWhat )
710 : {
711 304 : m_pLastOutputColor = NULL;
712 :
713 304 : if ( (_nWhat == FORMAT_CHANGE_TYPE::FORMATTER) && m_pFormatter )
714 64 : m_pFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_INTL_FORMAT );
715 :
716 304 : ReFormat();
717 304 : }
718 :
719 1 : void FormattedField::Commit()
720 : {
721 : // remember the old text
722 1 : OUString sOld( GetText() );
723 :
724 : // do the reformat
725 1 : ReFormat();
726 :
727 : // did the text change?
728 1 : if ( GetText() != sOld )
729 : { // consider the field as modified,
730 : // but we already have the most recent value;
731 : // don't reparse it from the text
732 : // (can lead to data loss when the format is lossy,
733 : // as is e.g. our default date format: 2-digit year!)
734 0 : impl_Modify(false);
735 1 : }
736 1 : }
737 :
738 421 : void FormattedField::ReFormat()
739 : {
740 421 : if (!IsEmptyFieldEnabled() || !GetText().isEmpty())
741 : {
742 47 : if (TreatingAsNumber())
743 : {
744 46 : double dValue = GetValue();
745 46 : if ( m_bEnableNaN && ::rtl::math::isNan( dValue ) )
746 421 : return;
747 46 : ImplSetValue( dValue, true );
748 : }
749 : else
750 1 : SetTextFormatted(GetTextValue());
751 : }
752 : }
753 :
754 36 : bool FormattedField::Notify(NotifyEvent& rNEvt)
755 : {
756 :
757 36 : if ((rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) && !IsReadOnly())
758 : {
759 0 : const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
760 0 : sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
761 0 : switch ( rKEvt.GetKeyCode().GetCode() )
762 : {
763 : case KEY_UP:
764 : case KEY_DOWN:
765 : case KEY_PAGEUP:
766 : case KEY_PAGEDOWN:
767 0 : if (!nMod && ImplGetFormatter()->IsTextFormat(m_nFormatKey))
768 : {
769 : // the base class would translate this into calls to Up/Down/First/Last,
770 : // but we don't want this if we are text-formatted
771 0 : return true;
772 : }
773 : }
774 : }
775 :
776 36 : if ((rNEvt.GetType() == MouseNotifyEvent::COMMAND) && !IsReadOnly())
777 : {
778 0 : const CommandEvent* pCommand = rNEvt.GetCommandEvent();
779 0 : if (pCommand->GetCommand() == CommandEventId::Wheel)
780 : {
781 0 : const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
782 0 : if ((pData->GetMode() == CommandWheelMode::SCROLL) && ImplGetFormatter()->IsTextFormat(m_nFormatKey))
783 : {
784 : // same as above : prevent the base class from doing Up/Down-calls
785 : // (normally I should put this test into the Up/Down methods itself, shouldn't I ?)
786 : // FS - 71553 - 19.01.00
787 0 : return true;
788 : }
789 : }
790 : }
791 :
792 36 : if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS)
793 : {
794 : // Sonderbehandlung fuer leere Texte
795 0 : if (GetText().isEmpty())
796 : {
797 0 : if (!IsEmptyFieldEnabled())
798 : {
799 0 : if (TreatingAsNumber())
800 : {
801 0 : ImplSetValue(m_dCurrentValue, true);
802 0 : Modify();
803 : }
804 : else
805 : {
806 0 : OUString sNew = GetTextValue();
807 0 : if (!sNew.isEmpty())
808 0 : SetTextFormatted(sNew);
809 : else
810 0 : SetTextFormatted(m_sDefaultText);
811 : }
812 0 : m_bValueDirty = false;
813 : }
814 : }
815 : else
816 : {
817 0 : Commit();
818 : }
819 : }
820 :
821 36 : return SpinField::Notify( rNEvt );
822 : }
823 :
824 58 : void FormattedField::SetMinValue(double dMin)
825 : {
826 : DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMinValue : only to be used in numeric mode !");
827 :
828 58 : m_dMinValue = dMin;
829 58 : m_bHasMin = true;
830 : // for checking the current value at the new border -> ImplSetValue
831 58 : ReFormat();
832 58 : }
833 :
834 58 : void FormattedField::SetMaxValue(double dMax)
835 : {
836 : DBG_ASSERT(m_bTreatAsNumber, "FormattedField::SetMaxValue : only to be used in numeric mode !");
837 :
838 58 : m_dMaxValue = dMax;
839 58 : m_bHasMax = true;
840 : // for checking the current value at the new border -> ImplSetValue
841 58 : ReFormat();
842 58 : }
843 :
844 0 : void FormattedField::SetTextValue(const OUString& rText)
845 : {
846 0 : SetText(rText);
847 0 : ReFormat();
848 0 : }
849 :
850 1 : void FormattedField::EnableEmptyField(bool bEnable)
851 : {
852 1 : if (bEnable == m_bEnableEmptyField)
853 2 : return;
854 :
855 0 : m_bEnableEmptyField = bEnable;
856 0 : if (!m_bEnableEmptyField && GetText().isEmpty())
857 0 : ImplSetValue(m_dCurrentValue, true);
858 : }
859 :
860 88 : void FormattedField::ImplSetValue(double dVal, bool bForce)
861 : {
862 :
863 88 : if (m_bHasMin && (dVal<m_dMinValue))
864 0 : dVal = m_dMinValue;
865 88 : if (m_bHasMax && (dVal>m_dMaxValue))
866 6 : dVal = m_dMaxValue;
867 88 : if (!bForce && (dVal == GetValue()))
868 94 : return;
869 :
870 : DBG_ASSERT(ImplGetFormatter() != NULL, "FormattedField::ImplSetValue : can't set a value without a formatter !");
871 :
872 82 : m_bValueDirty = false;
873 82 : m_dCurrentValue = dVal;
874 :
875 82 : OUString sNewText;
876 82 : if (ImplGetFormatter()->IsTextFormat(m_nFormatKey))
877 : {
878 : // first convert the number as string in standard format
879 9 : OUString sTemp;
880 9 : ImplGetFormatter()->GetOutputString(dVal, 0, sTemp, &m_pLastOutputColor);
881 : // then encode the string in the corresponding text format
882 9 : ImplGetFormatter()->GetOutputString(sTemp, m_nFormatKey, sNewText, &m_pLastOutputColor);
883 : }
884 : else
885 : {
886 73 : if( IsUsingInputStringForFormatting())
887 : {
888 0 : ImplGetFormatter()->GetInputLineString(dVal, m_nFormatKey, sNewText);
889 : }
890 : else
891 : {
892 73 : ImplGetFormatter()->GetOutputString(dVal, m_nFormatKey, sNewText, &m_pLastOutputColor);
893 : }
894 : }
895 :
896 82 : ImplSetTextImpl(sNewText, NULL);
897 82 : m_bValueDirty = false;
898 82 : DBG_ASSERT(CheckText(sNewText), "FormattedField::ImplSetValue : formatted string doesn't match the criteria !");
899 : }
900 :
901 290 : bool FormattedField::ImplGetValue(double& dNewVal)
902 : {
903 :
904 290 : dNewVal = m_dCurrentValue;
905 290 : if (!m_bValueDirty)
906 218 : return true;
907 :
908 72 : dNewVal = m_dDefaultValue;
909 72 : OUString sText(GetText());
910 72 : if (sText.isEmpty())
911 5 : return true;
912 :
913 : DBG_ASSERT(ImplGetFormatter() != NULL, "FormattedField::ImplGetValue : can't give you a current value without a formatter !");
914 :
915 67 : sal_uInt32 nFormatKey = m_nFormatKey; // IsNumberFormat changes the FormatKey!
916 :
917 67 : if (ImplGetFormatter()->IsTextFormat(nFormatKey) && m_bTreatAsNumber)
918 : // for detection of values like "1,1" in fields that are formatted as text
919 0 : nFormatKey = 0;
920 :
921 : // special treatment for percentage formatting
922 67 : if (ImplGetFormatter()->GetType(m_nFormatKey) == css::util::NumberFormat::PERCENT)
923 : {
924 : // the language of our format
925 0 : LanguageType eLanguage = m_pFormatter->GetEntry(m_nFormatKey)->GetLanguage();
926 : // the default number format for this language
927 0 : sal_uLong nStandardNumericFormat = m_pFormatter->GetStandardFormat(css::util::NumberFormat::NUMBER, eLanguage);
928 :
929 0 : sal_uInt32 nTempFormat = nStandardNumericFormat;
930 : double dTemp;
931 0 : if (m_pFormatter->IsNumberFormat(sText, nTempFormat, dTemp) &&
932 0 : css::util::NumberFormat::NUMBER == m_pFormatter->GetType(nTempFormat))
933 : // the string is equivalent to a number formatted one (has no % sign) -> append it
934 0 : sText += "%";
935 : // (with this, a input of '3' becomes '3%', which then by the formatter is translated
936 : // into 0.03. Without this, the formatter would give us the double 3 for an input '3',
937 : // which equals 300 percent.
938 : }
939 67 : if (!ImplGetFormatter()->IsNumberFormat(sText, nFormatKey, dNewVal))
940 13 : return false;
941 :
942 54 : if (m_bHasMin && (dNewVal<m_dMinValue))
943 0 : dNewVal = m_dMinValue;
944 54 : if (m_bHasMax && (dNewVal>m_dMaxValue))
945 0 : dNewVal = m_dMaxValue;
946 54 : return true;
947 : }
948 :
949 42 : void FormattedField::SetValue(double dVal)
950 : {
951 42 : ImplSetValue(dVal, m_bValueDirty);
952 42 : }
953 :
954 290 : double FormattedField::GetValue()
955 : {
956 :
957 290 : if ( !ImplGetValue( m_dCurrentValue ) )
958 : {
959 13 : if ( m_bEnableNaN )
960 0 : ::rtl::math::setNan( &m_dCurrentValue );
961 : else
962 13 : m_dCurrentValue = m_dDefaultValue;
963 : }
964 :
965 290 : m_bValueDirty = false;
966 290 : return m_dCurrentValue;
967 : }
968 :
969 10 : void FormattedField::Up()
970 : {
971 : // setValue handles under- and overflows (min/max) automatically
972 10 : SetValue(GetValue() + m_dSpinSize);
973 10 : SetModifyFlag();
974 10 : Modify();
975 :
976 10 : SpinField::Up();
977 10 : }
978 :
979 5 : void FormattedField::Down()
980 : {
981 5 : SetValue(GetValue() - m_dSpinSize);
982 5 : SetModifyFlag();
983 5 : Modify();
984 :
985 5 : SpinField::Down();
986 5 : }
987 :
988 5 : void FormattedField::First()
989 : {
990 5 : if (m_bHasMin)
991 : {
992 4 : SetValue(m_dMinValue);
993 4 : SetModifyFlag();
994 4 : Modify();
995 : }
996 :
997 5 : SpinField::First();
998 5 : }
999 :
1000 5 : void FormattedField::Last()
1001 : {
1002 5 : if (m_bHasMax)
1003 : {
1004 4 : SetValue(m_dMaxValue);
1005 4 : SetModifyFlag();
1006 4 : Modify();
1007 : }
1008 :
1009 5 : SpinField::Last();
1010 5 : }
1011 :
1012 0 : void FormattedField::UseInputStringForFormatting( bool bUseInputStr /* = true */ )
1013 : {
1014 0 : m_bUseInputStringForFormatting = bUseInputStr;
1015 0 : }
1016 :
1017 :
1018 51 : DoubleNumericField::~DoubleNumericField()
1019 : {
1020 17 : disposeOnce();
1021 34 : }
1022 :
1023 17 : void DoubleNumericField::dispose()
1024 : {
1025 17 : delete m_pNumberValidator;
1026 17 : FormattedField::dispose();
1027 17 : }
1028 :
1029 57 : void DoubleNumericField::FormatChanged(FORMAT_CHANGE_TYPE nWhat)
1030 : {
1031 57 : ResetConformanceTester();
1032 57 : FormattedField::FormatChanged(nWhat);
1033 57 : }
1034 :
1035 28 : bool DoubleNumericField::CheckText(const OUString& sText) const
1036 : {
1037 : // We'd like to implement this using the NumberFormatter::IsNumberFormat, but unfortunately, this doesn't
1038 : // recognize fragments of numbers (like, for instance "1e", which happens during entering e.g. "1e10")
1039 : // Thus, the roundabout way via a regular expression
1040 28 : return m_pNumberValidator->isValidNumericFragment( sText );
1041 : }
1042 :
1043 74 : void DoubleNumericField::ResetConformanceTester()
1044 : {
1045 : // the thousands and the decimal separator are language dependent
1046 74 : const SvNumberformat* pFormatEntry = ImplGetFormatter()->GetEntry(m_nFormatKey);
1047 :
1048 74 : sal_Unicode cSeparatorThousand = ',';
1049 74 : sal_Unicode cSeparatorDecimal = '.';
1050 74 : if (pFormatEntry)
1051 : {
1052 74 : LocaleDataWrapper aLocaleInfo( LanguageTag( pFormatEntry->GetLanguage()) );
1053 :
1054 148 : OUString sSeparator = aLocaleInfo.getNumThousandSep();
1055 74 : if (!sSeparator.isEmpty())
1056 74 : cSeparatorThousand = sSeparator[0];
1057 :
1058 74 : sSeparator = aLocaleInfo.getNumDecimalSep();
1059 74 : if (!sSeparator.isEmpty())
1060 148 : cSeparatorDecimal = sSeparator[0];
1061 : }
1062 :
1063 74 : delete m_pNumberValidator;
1064 74 : m_pNumberValidator = new validation::NumberValidator( cSeparatorThousand, cSeparatorDecimal );
1065 74 : }
1066 :
1067 17 : DoubleCurrencyField::DoubleCurrencyField(vcl::Window* pParent, WinBits nStyle)
1068 : :FormattedField(pParent, nStyle)
1069 17 : ,m_bChangingFormat(false)
1070 : {
1071 17 : m_bPrependCurrSym = false;
1072 :
1073 : // initialize with a system currency format
1074 17 : m_sCurrencySymbol = SvtSysLocale().GetLocaleData().getCurrSymbol();
1075 17 : UpdateCurrencyFormat();
1076 17 : }
1077 :
1078 188 : void DoubleCurrencyField::FormatChanged(FORMAT_CHANGE_TYPE nWhat)
1079 : {
1080 188 : if (m_bChangingFormat)
1081 : {
1082 94 : FormattedField::FormatChanged(nWhat);
1083 282 : return;
1084 : }
1085 :
1086 94 : switch (nWhat)
1087 : {
1088 : case FORMAT_CHANGE_TYPE::FORMATTER:
1089 : case FORMAT_CHANGE_TYPE::PRECISION:
1090 : case FORMAT_CHANGE_TYPE::THOUSANDSSEP:
1091 : // the aspects which changed don't take our currency settings into account (in fact, they most probably
1092 : // destroyed them)
1093 57 : UpdateCurrencyFormat();
1094 57 : break;
1095 : case FORMAT_CHANGE_TYPE::KEYONLY:
1096 : OSL_FAIL("DoubleCurrencyField::FormatChanged : somebody modified my key !");
1097 : // We always build our own format from the settings we get via special methods (setCurrencySymbol etc.).
1098 : // Nobody but ourself should modifiy the format key directly !
1099 0 : break;
1100 37 : default: break;
1101 : }
1102 :
1103 94 : FormattedField::FormatChanged(nWhat);
1104 : }
1105 :
1106 25 : void DoubleCurrencyField::setCurrencySymbol(const OUString& rSymbol)
1107 : {
1108 25 : if (m_sCurrencySymbol == rSymbol)
1109 33 : return;
1110 :
1111 17 : m_sCurrencySymbol = rSymbol;
1112 17 : UpdateCurrencyFormat();
1113 17 : FormatChanged(FORMAT_CHANGE_TYPE::CURRENCY_SYMBOL);
1114 : }
1115 :
1116 25 : void DoubleCurrencyField::setPrependCurrSym(bool _bPrepend)
1117 : {
1118 25 : if (m_bPrependCurrSym == _bPrepend)
1119 30 : return;
1120 :
1121 20 : m_bPrependCurrSym = _bPrepend;
1122 20 : UpdateCurrencyFormat();
1123 20 : FormatChanged(FORMAT_CHANGE_TYPE::CURRSYM_POSITION);
1124 : }
1125 :
1126 111 : void DoubleCurrencyField::UpdateCurrencyFormat()
1127 : {
1128 : // the old settings
1129 : LanguageType eLanguage;
1130 111 : GetFormat(eLanguage);
1131 111 : bool bThSep = GetThousandsSep();
1132 111 : sal_uInt16 nDigits = GetDecimalDigits();
1133 :
1134 : // build a new format string with the base class' and my own settings
1135 :
1136 : /* Strangely with gcc 4.6.3 this needs a temporary LanguageTag, otherwise
1137 : * there's
1138 : * error: request for member 'getNumThousandSep' in 'aLocaleInfo', which is
1139 : * of non-class type 'LocaleDataWrapper(LanguageTag)' */
1140 111 : LanguageTag aLanguageTag( eLanguage);
1141 222 : LocaleDataWrapper aLocaleInfo( aLanguageTag );
1142 :
1143 222 : OUStringBuffer sNewFormat;
1144 111 : if (bThSep)
1145 : {
1146 19 : sNewFormat.append('#');
1147 19 : sNewFormat.append(aLocaleInfo.getNumThousandSep());
1148 19 : sNewFormat.append("##0");
1149 : }
1150 : else
1151 92 : sNewFormat.append('0');
1152 :
1153 111 : if (nDigits)
1154 : {
1155 68 : sNewFormat.append(aLocaleInfo.getNumDecimalSep());
1156 :
1157 68 : OUStringBuffer sTemp;
1158 68 : comphelper::string::padToLength(sTemp, nDigits, '0');
1159 68 : sNewFormat.append(sTemp);
1160 : }
1161 :
1162 111 : if (getPrependCurrSym())
1163 : {
1164 30 : OUString sSymbol = getCurrencySymbol();
1165 30 : sSymbol = comphelper::string::stripStart(sSymbol, ' ');
1166 30 : sSymbol = comphelper::string::stripEnd(sSymbol, ' ');
1167 :
1168 60 : OUStringBuffer sTemp("[$");
1169 30 : sTemp.append(sSymbol);
1170 30 : sTemp.append("] ");
1171 30 : sTemp.append(sNewFormat);
1172 :
1173 : // for negative values : $ -0.00, not -$ 0.00 ...
1174 : // (the real solution would be a possibility to choose a "positive currency format" and a "negative currency format" ...
1175 : // But not now ... (and hey, you could take a formatted field for this ....))
1176 : // FS - 31.03.00 74642
1177 30 : sTemp.append(";[$");
1178 30 : sTemp.append(sSymbol);
1179 30 : sTemp.append("] -");
1180 30 : sTemp.append(sNewFormat);
1181 :
1182 60 : sNewFormat = sTemp;
1183 : }
1184 : else
1185 : {
1186 81 : OUString sTemp = getCurrencySymbol();
1187 81 : sTemp = comphelper::string::stripStart(sTemp, ' ');
1188 81 : sTemp = comphelper::string::stripEnd(sTemp, ' ');
1189 :
1190 81 : sNewFormat.append(" [$");
1191 81 : sNewFormat.append(sTemp);
1192 81 : sNewFormat.append(']');
1193 : }
1194 :
1195 : // set this new basic format
1196 111 : m_bChangingFormat = true;
1197 111 : SetFormat(sNewFormat.makeStringAndClear(), eLanguage);
1198 222 : m_bChangingFormat = false;
1199 909 : }
1200 :
1201 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|