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