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 //.......................................................................... 115 static void lcl_insertStopTransition( StateTransitions& _rRow ) 116 { 117 _rRow.insert( Transition( '_', END ) ); 118 } 119 120 //.......................................................................... 121 static void lcl_insertStartExponentTransition( StateTransitions& _rRow ) 122 { 123 _rRow.insert( Transition( 'e', EXPONENT_START ) ); 124 } 125 126 //.......................................................................... 127 static void lcl_insertSignTransitions( StateTransitions& _rRow, const State eNextState ) 128 { 129 _rRow.insert( Transition( '-', eNextState ) ); 130 _rRow.insert( Transition( '+', eNextState ) ); 131 } 132 133 //.......................................................................... 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 //.......................................................................... 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 //-------------------------------------------------------------------------- 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 //-------------------------------------------------------------------------- 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 //-------------------------------------------------------------------------- 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 322 FormattedField::StaticFormatter::StaticFormatter() 323 { 324 ++s_nReferences; 325 } 326 327 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 391 FormattedField::~FormattedField() 392 { 393 DBG_DTOR(FormattedField, NULL); 394 } 395 396 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 486 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 //------------------------------------------------------------------------------ 497 void FormattedField::EnableNotANumber( sal_Bool _bEnable ) 498 { 499 if ( m_bEnableNaN == _bEnable ) 500 return; 501 502 m_bEnableNaN = _bEnable; 503 } 504 505 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 686 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 716 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 760 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 948 void FormattedField::SetTextValue(const XubString& rText) 949 { 950 DBG_CHKTHIS(FormattedField, NULL); 951 SetText(rText); 952 ReFormat(); 953 } 954 955 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 1059 void FormattedField::SetValue(double dVal) 1060 { 1061 DBG_CHKTHIS(FormattedField, NULL); 1062 ImplSetValue(dVal, m_bValueDirty); 1063 } 1064 1065 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 1134 void FormattedField::UseInputStringForFormatting( bool bUseInputStr /* = true */ ) 1135 { 1136 m_bUseInputStringForFormatting = bUseInputStr; 1137 } 1138 1139 //------------------------------------------------------------------------------ 1140 bool FormattedField::IsUsingInputStringForFormatting() const 1141 { 1142 return m_bUseInputStringForFormatting; 1143 } 1144 1145 1146 //============================================================================== 1147 //------------------------------------------------------------------------------ 1148 DoubleNumericField::~DoubleNumericField() 1149 { 1150 #ifdef REGEXP_SUPPORT 1151 delete m_pConformanceTester; 1152 #else 1153 delete m_pNumberValidator; 1154 #endif 1155 } 1156 1157 //------------------------------------------------------------------------------ 1158 void DoubleNumericField::FormatChanged(FORMAT_CHANGE_TYPE nWhat) 1159 { 1160 ResetConformanceTester(); 1161 FormattedField::FormatChanged(nWhat); 1162 } 1163 1164 //------------------------------------------------------------------------------ 1165 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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