00001 // $Id: convert.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 // These functions provide conversion between Millipoints and Strings. 00099 00100 /* Author: Rik 00101 Created: 11/5/93 00102 Purpose: These functions will provide a means of converting from Doc Coords (millipoints) 00103 to Strings and visa versa. For example, convert 72000 millipoints to the string 00104 1in or 72pt as well as converting from the string '1in72pt' to 144000 00105 millipoints. The units to convert to can be chosen, as can the number of 00106 decimal points. When converting from string back to millipoints, all the valid 00107 units are added together. If an error is detected (ie '4cm72zx' ), then 00108 everything up to the error will be used (4cm). */ 00109 00110 00111 00112 // Better find out about the string class and all the other types and stuff 00113 00114 #include "camtypes.h" // Good ol' Camtypes 00115 //#include "ccmaths.h" // 64 bit muldiv - in camtypes.h [AUTOMATICALLY REMOVED] 00116 //#include "convert.h" // function prototypes - in camtypes.h [AUTOMATICALLY REMOVED] 00117 //#include "markn.h" // For unit constants 00118 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00119 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00120 //#include "units.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00121 //#include "app.h" // Camelot object - in camtypes.h [AUTOMATICALLY REMOVED] 00122 //#include "peter.h" // _R(IDS_MEMORYFORMAT_BYTE) ... 00123 #include "localenv.h" // for locale string settings 00124 //#include "richard3.h" // more naughty inline strings... 00125 00126 00127 // Put my version number into the About box 00128 DECLARE_SOURCE( "$Revision: 1282 $" ); 00129 00130 // Declare smart memory handling in Debug builds 00131 #define new CAM_DEBUG_NEW 00132 00133 CC_IMPLEMENT_DYNAMIC(DimScale, CCObject) 00134 00135 // Set up the defaults for the Convert class 00136 00137 // The default DimScale object is an inactive one that is used as a fall-back in the 00138 // frightening event of one not being found by DimScale::GetPtrDimScale(Node*) 00139 DimScale* pDefaultDimScale = NULL; 00140 00141 char Convert::DecimalPoint = '.'; // Character to separate whole part of number from fractional part 00142 char Convert::ThousandSep = ','; // Char to separate thousands, e.g. 10,000 00143 char Convert::MinusSign = '-'; // What to show if go less than zero 00144 UINT32 Convert::NumDecimalPlaces = 2; // Number of decimal places to display to by default 00145 00146 /****************************************************************************************** 00147 00148 > static BOOL Convert::Init() 00149 00150 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00151 Created: 25/1/95 00152 Inputs: - 00153 Outputs: - 00154 Returns: - 00155 Purpose: AppPrefsDlg Init method. Called when the kernel initialises. 00156 It reads from the Windows ini file the settings for things like the 00157 current decimal point character, thousands separator and number of 00158 decimal places and stores these for later use. 00159 SeeAlso: GetCurrentNumberFormat(); 00160 00161 ******************************************************************************************/ 00162 00163 BOOL Convert::Init() 00164 { 00165 00166 // // Declare any preferences that we require. 00167 // if ( Camelot.DeclareSection(TEXT("Preferences"), 3) ) 00168 // { 00169 // // section declared ok so now define the preference option 00170 // Camelot.DeclarePref(TEXT("Preferences"), TEXT("DecimalPointChar"), &DecimalPoint, 0, 255); 00171 // Camelot.DeclarePref(TEXT("Preferences"), TEXT("ThousandSepChar"), &ThousandSep, 0, 255); 00172 // } 00173 00174 // Get the current details from the OS about the number format specified by the user 00175 // If fails then return this to the caller. 00176 return GetCurrentNumberFormat(); 00177 } 00178 00179 /******************************************************************************************** 00180 00181 > static BOOL Convert::GetCurrentNumberFormat() 00182 00183 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00184 Created: 12/9/95 00185 Inputs: - 00186 Outputs: - 00187 Returns: - 00188 Purpose: Read from the operating system what the user has defined to be their decimal 00189 point character and thousands separator character and store these in the 00190 class variables. 00191 It is now also called from the mainframe message handler, when it 00192 receives a WM_WININICHANGE message. 00193 Errors: - 00194 SeeAlso: CMainFrame::OnWinIniChange() 00195 00196 ********************************************************************************************/ 00197 00198 BOOL Convert::GetCurrentNumberFormat() 00199 { 00200 String_8 ThousandsSepStr( _T(",") ); 00201 String_8 DecimalPointStr( _T(".") ); 00202 NumDecimalPlaces = 2; 00203 00204 // Read from the operating system what the user has defined to be their decimal point 00205 // character and thousands separator character. 00206 LocalEnvironment::GetThousandsSeparator(&ThousandsSepStr); 00207 LocalEnvironment::GetDecimalPointChar(&DecimalPointStr); 00208 LocalEnvironment::GetNumberOfDecimalPlaces(&NumDecimalPlaces); 00209 00210 // Set up the static char variables to reflect these 00211 ThousandSep = ((TCHAR *) ThousandsSepStr)[0]; 00212 DecimalPoint = ((TCHAR *) DecimalPointStr)[0]; 00213 00214 // Check for "testing" of internationalisation. 00215 ERROR3IF(ThousandSep == DecimalPoint, 00216 "Convert::GetCurrentNumberFormat: decimal point and " 00217 "thousands separator are the same"); 00218 00219 //char to TCHAR for DBCS 00220 TRACEUSER( "Neville", wxT("InitConvert() ThousandsSepStr=%s\n"), (TCHAR *)ThousandsSepStr ); 00221 TRACEUSER( "Neville", wxT("InitConvert() DecimalPointStr=%s\n"), (TCHAR *)DecimalPointStr ); 00222 TRACEUSER( "Neville", wxT("InitConvert() NumDecimalPlaces=%d\n"), NumDecimalPlaces ); 00223 00224 return TRUE; 00225 } 00226 00227 00228 /******************************************************************************************** 00229 00230 > static char Convert::GetDecimalPointChar() 00231 00232 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00233 Created: 12/9/95 00234 Inputs: - 00235 Outputs: - 00236 Returns: The current decimal point character being used. 00237 Purpose: To find out what the current decimal point character is. 00238 SeeAlso: SetDecimalPointChar(); GetCurrentNumberFormat(); 00239 00240 ********************************************************************************************/ 00241 00242 char Convert::GetDecimalPointChar() 00243 { 00244 return DecimalPoint; 00245 } 00246 00247 /******************************************************************************************** 00248 00249 > static char Convert::GetThousandsSepChar() 00250 00251 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00252 Created: 12/9/95 00253 Inputs: - 00254 Outputs: - 00255 Returns: The current thousands separator character being used. 00256 Purpose: To find out what the current thousands separator character is. 00257 SeeAlso: SetThousandsSepChar(); GetCurrentNumberFormat(); 00258 00259 ********************************************************************************************/ 00260 00261 char Convert::GetThousandsSepChar() 00262 { 00263 return ThousandSep; 00264 } 00265 00266 00267 /******************************************************************************************** 00268 00269 > static UINT32 Convert::GetNumberDecimalPlaces() 00270 00271 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00272 Created: 12/9/95 00273 Inputs: - 00274 Outputs: - 00275 Returns: The current number of decimal places being used. 00276 Purpose: To find out what the current number of decimal places is. 00277 SeeAlso: SetNumberDecimalPlaces(); 00278 00279 ********************************************************************************************/ 00280 00281 UINT32 Convert::GetNumberDecimalPlaces() 00282 { 00283 return NumDecimalPlaces; 00284 } 00285 00286 /******************************************************************************************** 00287 00288 > static BOOL Convert::SetDecimalPointChar(char NewDecimalPoint) 00289 00290 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00291 Created: 12/9/95 00292 Inputs: - 00293 Outputs: - 00294 Returns: True if set correctly, False otherwise. 00295 Purpose: Allows the setting up of the character to separate whole part of number from 00296 the fractional part in displayed numbers e.g. 56.79 00297 This is read from the OS at present. This function just provided just in case 00298 we wish to overide this in the future. 00299 SeeAlso: GetDecimalPointChar(); GetCurrentNumberFormat(); 00300 00301 ********************************************************************************************/ 00302 00303 BOOL Convert::SetDecimalPointChar(char NewDecimalPoint) 00304 { 00305 // Don't allow a blank to be set. 00306 //if (NewDecimalPoint = '') return FALSE; 00307 00308 DecimalPoint = NewDecimalPoint; 00309 00310 return TRUE; 00311 } 00312 00313 /******************************************************************************************** 00314 00315 > static BOOL Convert::SetThousandsSepChar(char NewThousandsSep) 00316 00317 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00318 Created: 12/9/95 00319 Inputs: - 00320 Outputs: - 00321 Returns: True if set correctly, False otherwise. 00322 Purpose: Allows the setting up of the character to be used to separate thousands in 00323 displayed numbers e.g. 10,000. 00324 This is read from the OS at present. This function just provided just in case 00325 we wish to overide this in the future. 00326 00327 SeeAlso: GetThousandsSepChar(); GetCurrentNumberFormat(); 00328 00329 ********************************************************************************************/ 00330 00331 BOOL Convert::SetThousandsSepChar(char NewThousandsSep) 00332 { 00333 // Don't allow a blank to be set. 00334 //if (NewThousandsSep = '') return FALSE; 00335 00336 ThousandSep = NewThousandsSep; 00337 00338 return TRUE; 00339 } 00340 00341 /******************************************************************************************** 00342 00343 > static BOOL Convert::SetNumberDecimalPlaces(UINT32 NewDPs) 00344 00345 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00346 Created: 12/9/95 00347 Inputs: NewDPs new number of decimal places to use 00348 Outputs: - 00349 Returns: True if set correctly, False otherwise. 00350 Purpose: Allows the setting up of the number of decimal places to display to by default 00351 This is read from the OS at present. This function just provided just in case 00352 we wish to overide this in the future. 00353 SeeAlso: GetNumberDecimalPlaces(); GetCurrentNumberFormat(); 00354 00355 ********************************************************************************************/ 00356 00357 BOOL Convert::SetNumberDecimalPlaces(UINT32 NewDPs) 00358 { 00359 // Set some limit to the number allowed 00360 if (NewDPs > 9) return FALSE; 00361 00362 NumDecimalPlaces = NewDPs; 00363 00364 return TRUE; 00365 } 00366 00367 00368 /****************************************************************************************** 00369 00370 > static BOOL Convert::ReplaceDecimalPoint(StringBase* pString) 00371 00372 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00373 Created: 27/1/95 00374 Inputs: pString - Pointer to the string to be parsed. 00375 Outputs: pString - Pointer to the string that should now have the proper decimal point 00376 Returns: TRUE if the conversion worked, false otherwise 00377 Purpose: Searches the specified string for a decimal point and replaces this with the 00378 specified DecimalPoint character. It assumes that a check has been made 00379 already to see if we are using a non-decimal point character and so this 00380 routine is only called when the replacement is actually required. 00381 This MUST ALWAYS be after the StripTrailingZeros code. Otherwise, the 00382 StripTrailingZeros code would have to search for two items, a decimal point 00383 and the international form of the decimal point. 00384 00385 SeeAlso: MillipointsToString; DimScale::ConvertToUnits; DoubleToString; 00386 Convert::StripTrailingZeros; 00387 00388 ********************************************************************************************/ 00389 00390 BOOL Convert::ReplaceDecimalPoint(StringBase* pString) 00391 { 00392 // Could probably be optimised to be quicker 00393 00394 // Make up a string of the new decimal point character 00395 String_8 InsertStr; 00396 ((TCHAR *) InsertStr)[0] = DecimalPoint; 00397 ((TCHAR *) InsertStr)[1] = 0; 00398 00399 // Work out the position of the current decimal point character, - 1 if none 00400 INT32 Position; 00401 String_8 InsertMark(_R(IDS_CONVERT_DP_CHAR)); 00402 00403 Position = pString->Sub(InsertMark); 00404 00405 // If decimal point was found then put the new decimal point character in place 00406 if (Position > 0) 00407 { 00408 pString->Remove(Position, 1); 00409 pString->Insert(InsertStr, Position); 00410 } 00411 00412 return TRUE; 00413 } 00414 00415 /******************************************************************************************** 00416 00417 > static BOOL Convert::StripTrailingZeros(StringBase* pString) 00418 00419 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00420 Created: 12/7/95 00421 Inputs: pString - string to have trailing zeros removed 00422 Outputs: pString - string with trailing zeros removed 00423 Returns: FALSE if fails 00424 Purpose: Strip trailing zeros (& decimal point) from a string containing a decimal number 00425 This MUST ALWAYS be called before the replace decimal point character code. 00426 Otherwise, we would have to search for two items, a decimal point and the 00427 international form of the decimal point. 00428 SeeAlso: MillipointsToString; DimScale::ConvertToUnits; DoubleToString; 00429 Convert::ReplaceDecimalPoint; 00430 00431 ********************************************************************************************/ 00432 00433 BOOL Convert::StripTrailingZeros(StringBase* pString) 00434 { 00435 // Get the decimal point character that we are going to search for into one of our 00436 // strings. This MUST be the decimal point character as this is ALWAYS called before 00437 // the replace decimal point character. Otherwise, we would have to search for two 00438 // items. 00439 String_8 DPChar(_R(IDS_CONVERT_DP_CHAR)); 00440 const String_8 ZeroChar(_R(IDS_CONVERT_ZERO_CHAR)); 00441 00442 // if there is a decimal point in the string ... 00443 if (pString->Sub(DPChar)!=-1) 00444 { 00445 // skip backwards over trailing zeros 00446 String_8 TmpStr; 00447 INT32 NewStrLen = pString->Length(); 00448 do 00449 { 00450 NewStrLen-=1; 00451 pString->Mid(&TmpStr,NewStrLen,1); 00452 } while (TmpStr==ZeroChar); 00453 00454 // if this previous char is NOT a decimal point DO NOT strip it 00455 if (TmpStr!=DPChar) 00456 NewStrLen+=1; 00457 00458 // remove the trailing zeros from the original string 00459 pString->Left(pString,NewStrLen); 00460 } 00461 00462 return TRUE; 00463 } 00464 00465 00466 /******************************************************************************************** 00467 00468 > static BOOL Convert::IsCharUnitType(TCHAR Char) 00469 00470 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00471 Created: 27/6/94 00472 Inputs: Char - the character to check 00473 Outputs: - 00474 Returns: TRUE - This could be part of a unit type specifier 00475 FALSE - Sorry, but it's either a white space or a number 00476 Purpose: Checks to see if this char could be part of a string that specifies a unit 00477 We have to allow most chars so that arbitrary units can be defined like such 00478 as pounds, dollars or percentages 00479 Illegal unit specifier chars are :- 00480 ASCII value <= ' ' 00481 Numericals - '1', '2', etc 00482 Minus sign - '-' 00483 Decimal point - '.' 00484 Thousand separator - ',' as in "10,000" 00485 Errors: - 00486 00487 ********************************************************************************************/ 00488 00489 BOOL Convert::IsCharUnitType(TCHAR Char) 00490 { 00491 return ( (unsigned(Char) > unsigned(TEXT(' '))) && 00492 (!StringBase::IsNumeric(Char)) && 00493 (Char != MinusSign) && 00494 (Char != DecimalPoint) && 00495 (Char != ThousandSep) 00496 ); 00497 } 00498 00499 /******************************************************************************************** 00500 00501 > static BOOL Convert::IsCharStartOfNumber(TCHAR Char) 00502 00503 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00504 Created: 27/6/94 00505 Inputs: Char - the character to check 00506 Outputs: - 00507 Returns: TRUE - This could be the first char of a number 00508 FALSE - Sorry, but it's definitely not a number 00509 Purpose: Checks to see if this char could be the first char in a string that specifies 00510 a number 00511 Legal number-starting chars are :- 00512 Numericals - '1', '2', etc 00513 Minus sign - '-' 00514 Decimal point - '.' 00515 Errors: - 00516 00517 ********************************************************************************************/ 00518 00519 BOOL Convert::IsCharStartOfNumber(TCHAR Char) 00520 { 00521 return ( (StringBase::IsNumeric(Char)) || 00522 (Char == MinusSign) || 00523 (Char == DecimalPoint) 00524 ); 00525 } 00526 00527 /******************************************************************************************** 00528 00529 > static BOOL Convert::ReadUnitType(StringBase* pStr,INT32* pPos,UnitType* pUnitType) 00530 00531 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00532 Created: 27/6/94 00533 Inputs: pStr - Ptr to the string to get unit type 00534 pPos - *pPos = the pos to start scannning the string from (0 is first char) 00535 pUnitType - Ptr to a UnitType 00536 Outputs: *pPos is the pos the scanning stopped 00537 *pUnitType is the units represented by the string 00538 Returns: TRUE - units have been recognised and value stored in *pUnitType is valid 00539 OR 00540 no units have been specified and *pUnitType == NOTYPE 00541 FALSE - What are these units eh? 00542 Purpose: General purpose routine for extracting the unit type from a string 00543 E.g. "42cm45mm" with *pPos = 2 returns TRUE with *pUnitType == CENTIMETRES & *pPos == 4 00544 "42cm45mm" with *pPos = 6 returns TRUE with *pUnitType == MILLIMETRES & *pPos == 8 00545 Errors: - 00546 00547 ********************************************************************************************/ 00548 00549 BOOL Convert::ReadUnitType(const StringBase &Str,INT32* pPos,UnitType* pUnitType) 00550 { 00551 INT32 len = Str.Length(); 00552 const TCHAR *pChar = (const TCHAR *)Str; 00553 TCHAR UnitCharArray[256]; 00554 INT32 i; 00555 BOOL ok = TRUE; 00556 //Added for DBCS; Strip leading crap 00557 while (*pPos < len && iswspace(pChar[*pPos])) //while (*pPos < len && pChar[*pPos] <= ' ') 00558 (*pPos)++ ; 00559 00560 i = 0; 00561 if (IsCharUnitType(pChar[*pPos])) 00562 { 00563 // Copy unit-specifying chars into UnitCharArray 00564 // NO LONGER copes with wierd unit specifiers that contain numbers too. e.g. "nu2", "b54c" 00565 // as of 18/5/95 (MarkN) 00566 while ( *pPos < len && (IsCharUnitType(pChar[*pPos])) && i<256) // || StringBase::IsNumeric(pChar[*pPos])) && 00567 UnitCharArray[i++] = pChar[(*pPos)++]; 00568 } 00569 00570 UnitCharArray[i] = 0; // Visit the string Terminator (I'm a null char; that's what I do) 00571 00572 String_256 UnitString = UnitCharArray; 00573 00574 //char changed to TCHAR for DBCS 00575 // TCHAR* p = UnitString; // for debugging purposes 00576 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList(); 00577 00578 if (!UnitString.IsEmpty()) 00579 { 00580 // if the string isn't empty, then we must recognise the unit 00581 // otherwise we'll have to fail 00582 *pUnitType = pDocUnitList->FindUnitType(UnitString); 00583 ok = (*pUnitType != NOTYPE); 00584 } 00585 else 00586 *pUnitType = NOTYPE; // Empty string means NOTYPE means use a default type from somewhere 00587 00588 00589 return (ok); 00590 } 00591 00592 00593 /******************************************************************************************** 00594 00595 > static BOOL Convert::ReadNumber(StringBase* pStr,INT32* pPos,double* pResult) 00596 00597 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00598 Created: 27/6/94 00599 Inputs: pStr - Ptr to the string to get value from 00600 pPos - *pPos = the pos to start scannning the string from (0 is first char) 00601 pResult - Ptr to a double 00602 Outputs: *pPos is the pos the scanning stopped 00603 *pResult = The number represented at the specified portion of the string 00604 Returns: TRUE - a valid number was read 00605 FALSE - something's a bit dodgey about that number mate 00606 Purpose: General purpose routine for extracting the number from a string 00607 E.g. "42cm45.7mm" with *pPos == 0 returns TRUE with *pResult and 42.0 & *pPos == 2 00608 "42cm-45.7mm" with *pPos == 4 returns TRUE with *pResult and -45.7 & *pPos == 9 00609 Errors: - 00610 00611 ********************************************************************************************/ 00612 00613 BOOL Convert::ReadNumber( const StringBase &Str,INT32* pPos,double* pResult) 00614 { 00615 INT32 len = Str.Length(); 00616 const TCHAR *pChar = Str; 00617 BOOL IsNegative = FALSE; 00618 double Number = 0.0; 00619 00620 //Added for DBCS Strip leading crap 00621 while (*pPos < len && iswspace(pChar[*pPos])) //while (*pPos < len && pChar[*pPos] <= ' ') 00622 (*pPos)++; 00623 00624 // Check for a minus sign; Added for DBCS 00625 if( pChar[*pPos] == MinusSign ) //if ( pChar[*pPos] == MinusSign ) 00626 { 00627 IsNegative = TRUE; 00628 (*pPos)++; 00629 if (*pPos >= len) return FALSE; 00630 } 00631 00632 // Get the actual number Added for DBCS 00633 while( *pPos < len && 00634 ( StringBase::IsNumeric(pChar[*pPos]) || 00635 pChar[*pPos] == ThousandSep ) )//|| pChar[*pPos] == ThousandSep) ) 00636 { 00637 //Added for DBCS 00638 if (pChar[*pPos] != ThousandSep ) //if (pChar[*pPos] != ThousandSep) 00639 { 00640 Number = (Number * 10.0) + ( pChar[*pPos] - TEXT('0') ); 00641 } 00642 (*pPos)++; 00643 } 00644 00645 // Check for a decimal place; Added for DBCS 00646 if ( pChar[*pPos] == DecimalPoint) //if ( pChar[*pPos] == DecimalPoint ) 00647 { 00648 (*pPos)++; 00649 if (*pPos < len) // If the string ends in a DP, then we return the number now 00650 { 00651 // Otherwise, we continue reading the fractional part of the string... 00652 INT32 DecimalFactor = 10; 00653 while ( *pPos < len && StringBase::IsNumeric(pChar[*pPos]) ) 00654 { 00655 Number += (double)( pChar[*pPos] - TEXT('0') ) / DecimalFactor; 00656 DecimalFactor *= 10; 00657 (*pPos)++; 00658 } 00659 } 00660 } 00661 00662 // If the number started with a minus sign, then make sure it is negative 00663 if (IsNegative) 00664 Number = -Number; 00665 00666 *pResult = Number; 00667 return TRUE; 00668 } 00669 00670 /******************************************************************************************** 00671 00672 > static double Convert::ConvertToNewUnits(double Value,UnitType Units,UnitType NewUnits) 00673 00674 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00675 Created: 27/6/94 00676 Inputs: Value - value to convert 00677 OldUnits- units Value is defined in 00678 NewUnits- the units you want Value to be converted toTYPE 00679 Outputs: - 00680 Returns: The new value 00681 Purpose: Used convert one value into an equivalent value in another unit base 00682 E.g. ConvertToNewUnits(3,CENTIMETRES,MILLIMETRES) would return 30.0 00683 because 3cm == 30mm 00684 00685 ********************************************************************************************/ 00686 00687 double Convert::ConvertToNewUnits(double Value,UnitType OldUnits,UnitType NewUnits) 00688 { 00689 ENSURE(NewUnits != NOTYPE,"Can't convert to NOTYPE units"); 00690 00691 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList(); 00692 Unit* pNewUnit = pDocUnitList->FindUnit(NewUnits); 00693 double NumMillipoints = 1.0; 00694 00695 if (OldUnits != NOTYPE) 00696 { 00697 Unit* pOldUnit = pDocUnitList->FindUnit(OldUnits); 00698 NumMillipoints = Value * pOldUnit->GetMillipoints(); 00699 } 00700 else 00701 NumMillipoints = Value; 00702 00703 return (NumMillipoints / pNewUnit->GetMillipoints()); 00704 } 00705 00706 /******************************************************************************************** 00707 00708 > Static BOOL Convert::StringToComponents(StringBase* InputString, 00709 double* pValue, UnitType* pUnits) 00710 00711 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00712 Created: 14/6/94 (changed considerably on 27/6/94 by Markn) 00713 Inputs: InputString - The string to get values from 00714 pValue - The value of the numerical part of the string 00715 pUnits - The unit value of the unit part of the string 00716 if no units are specified, *pUnits = NOTYPE 00717 Outputs: - 00718 Returns: TRUE - Valid string 00719 FALSE - Something wrong with the string 00720 Purpose: General purpose routine for extracting the value and unit components of a string. 00721 E.g.1 the string "42.6in" would extract the value 42.6 and the unit type INCHES 00722 E.g.2 The string "42.6" would give *pValue=42.6,*pUnits=NOTYPE, and TRUE is returned. 00723 E.g.3 "4in5in" gives *pValue=9,*pUnits=INCHES, and returns TRUE 00724 E.g.4 "1in2cm" gives *pValue = 1.79,*pUnits=INCHES, and returns TRUE 00725 In this case it takes the first unit specified as the dominant unit (INCHES in this 00726 case), so the result is 1in plus 2cm converted to INCHES which is about 0.79in 00727 Errors: This function can fail if the string was not a valid one. ie the 00728 string '12zx'. zx is not a unit that Camelot understands 00729 and so fails. 00730 00731 ********************************************************************************************/ 00732 00733 BOOL Convert::StringToComponents( const StringBase &str,double* pValue,UnitType* pUnits) 00734 { 00735 TCHAR* MyString; 00736 TCHAR Char; 00737 INT32 Pos = 0; 00738 INT32 len = str.Length(); 00739 String_256 InputString( str ); 00740 // BOOL IsNegative = FALSE; 00741 double Result = 0.0; 00742 UnitType MainUnits = NOTYPE; 00743 00744 *pValue = 1.0; 00745 *pUnits = INCHES; 00746 00747 // Make sure that the string is in lower case as per SI units 00748 InputString.toLower(); 00749 MyString = (TCHAR *)InputString; 00750 00751 // I might consider adding this to the base class StringBase, BUT at the moment 00752 // its not really necessary .... 00753 // 00754 // JCF: fixed this to be internationally portable ie. what is alphanumeric in 00755 // your language? 00756 // 00757 while (Pos < len) 00758 { 00759 if (!StringBase::IsAlphaNumeric(MyString[Pos]) && 00760 MyString[Pos] != TEXT('-') && 00761 MyString[Pos] != TEXT('.') && 00762 MyString[Pos] != TEXT(',')) 00763 { 00764 return FALSE; 00765 } 00766 00767 Pos++; 00768 } 00769 00770 Pos = 0; 00771 00772 while (Pos < len) 00773 { 00774 double Number = 0.0; 00775 UnitType Units; 00776 00777 // Strip leading crap Added for DBCS 00778 while (Pos < len && iswspace( MyString[Pos] )) //while (Pos < len && MyString[Pos] <= ' ') 00779 Pos++; 00780 00781 Char = MyString[Pos]; 00782 00783 if (IsCharStartOfNumber(Char)) 00784 { 00785 if (!ReadNumber(InputString,&Pos,&Number)) 00786 return FALSE; 00787 if (!ReadUnitType(InputString,&Pos,&Units)) 00788 return FALSE; 00789 } 00790 else 00791 { 00792 if (!ReadUnitType(InputString,&Pos,&Units)) 00793 return FALSE; 00794 if (!ReadNumber(InputString,&Pos,&Number)) 00795 return FALSE; 00796 } 00797 00798 if (MainUnits == NOTYPE) MainUnits = Units; 00799 00800 if (MainUnits != Units && MainUnits != NOTYPE) 00801 Number = ConvertToNewUnits(Number,Units,MainUnits); 00802 00803 Result += Number; 00804 } 00805 00806 *pUnits = MainUnits; 00807 *pValue = Result; 00808 00809 return TRUE; 00810 } 00811 00812 /******************************************************************************************** 00813 00814 > static double Convert::StringToDouble( StringBase* pInputString, UnitType Default, 00815 BOOL* ValidString ) 00816 00817 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00818 Created: 8/3/94 - modified 14/6/94 00819 Inputs: pInputString - The string to convert to its millipoint value 00820 Default - the Unit type to be used if no other units have been 00821 specified in the string 00822 Outputs: ValidString - The Address of a bool. This will be set to TRUE if 00823 the function converted the string without error, FALSE otherwise. 00824 Returns: double - the number of Millipoints represented by the string 00825 Purpose: Convert the string into a floating point representation of the number of 00826 millipoints. eg '1in' would be converted to 72000.0 millipoints. 00827 Does NOT cope with '0.25in0.75in' - this would return 18000.0 millipoints 00828 instead of 72000.0 millipoints. 00829 If you want a MILLIPOINT value, use StringToMillipoint to ensure correct 00830 rounding. 00831 Errors: This function can fail if the string was not a valid one. ie the 00832 string '12zx'. zx is not a unit that StringToDouble understands 00833 and so fails. 00834 SeeAlso: StringToMillipoint 00835 00836 ********************************************************************************************/ 00837 00838 double Convert::StringToDouble( const StringBase &InputString, UnitType Default, BOOL* ValidString ) 00839 { 00840 double Number = 1.0; 00841 UnitType Units; 00842 00843 *ValidString = StringToComponents( InputString,&Number,&Units); 00844 00845 if (Units == NOTYPE) 00846 Units = Default; 00847 00848 if (*ValidString) 00849 { 00850 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList(); 00851 Unit* pUnit = pDocUnitList->FindUnit(Units); 00852 return (Number * pUnit->GetMillipoints()); // Get the number to millipoints and multiply 00853 } 00854 else 00855 return 72000.0; 00856 } 00857 00858 00859 /******************************************************************************************** 00860 00861 > static MILLIPOINT Convert::StringToMillipoints( StringBase* pInputString, UnitType Default, 00862 BOOL* ValidString ) 00863 00864 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00865 Created: 8/3/94 - modified 14/6/94 00866 Inputs: pInputString - The string to convert to its millipoint value 00867 Default - the Unit type to be used if no other units have been 00868 specified in the string 00869 Outputs: ValidString - The Address of a bool. This will be set to TRUE if 00870 the function converted the string without error, FALSE otherwise. 00871 Returns: MILLIPOINT - An integer version of the number of Millipoints represented by 00872 the string 00873 Purpose: Convert the string into a MILLIPOINT representation of the number of 00874 millipoints. eg '1in' would be converted to 72000 millipoints. 00875 Does NOT cope with '0.25in0.75in' - this would return 18000 millipoints 00876 instead of 72000 millipoints. 00877 Errors: This function can fail if the string was not a valid one. ie the 00878 string '12zx'. zx is not a unit that StringToDouble understands 00879 and so fails. 00880 00881 ********************************************************************************************/ 00882 00883 MILLIPOINT Convert::StringToMillipoints( const StringBase &InputString, UnitType Default, BOOL* ValidString ) 00884 { 00885 double result = StringToDouble( InputString,Default,ValidString); 00886 00887 return (MILLIPOINT)(result+0.5); 00888 } 00889 00890 00891 /******************************************************************************************** 00892 00893 > static void Convert::NumberToString( MILLIPOINT Number, StringBase* MyString ) 00894 00895 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00896 Created: 1/9/93 00897 Inputs: Number - The number to be turned into a string 00898 Outputs: MyString - the string is appended to this string 00899 Purpose: Appends the string representation of the given number to the end 00900 of MyString 00901 00902 ********************************************************************************************/ 00903 00904 void Convert::NumberToString( MILLIPOINT Number, StringBase* MyString ) 00905 { 00906 INT32 Factor = 1; 00907 TCHAR ch[2]; 00908 ch[1] = TEXT('\0'); 00909 00910 // Get a factor that 00911 while (Factor*10 <= Number) 00912 Factor *= 10; 00913 00914 while (Factor > 1) 00915 { 00916 // calculate the most significant digit and remove it from the number 00917 INT32 Digit = INT32(Number / Factor); 00918 ch[0] = TEXT('0') + Digit; 00919 *MyString += String_8(ch); 00920 00921 // Add the digit into the string 00922 Number = Number - (Digit*Factor); 00923 Factor /= 10; 00924 } 00925 00926 // add in the last character 00927 ch[0] = TEXT('0') + (INT32)Number; 00928 *MyString += String_8(ch); 00929 00930 } 00931 00932 00933 00934 00935 /******************************************************************************************** 00936 00937 > static BOOL Convert::MillipointsToString( double MpValue, UnitType TheUnit, 00938 StringBase* OutputString, INT32 DecimalPlaces = -1) 00939 00940 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> (rewritten by MarkN to use new units system - 6/7/94) 00941 Created: 1/9/93 00942 Inputs: MpValue - The number of millipoints to be converted 00943 TheUnit - The units that you need the result in 00944 OutputString - Stirng to put value into (See outputs) 00945 DecimalPlaces - The number of Decimal places required (0-3). This defaults to 00946 -1 which means use the default preference value. 00947 Outputs: OutputString - pointer to a string that is big enough to hold 00948 the resulting number plus its type (ie 12.45cm) 00949 Returns: TRUE if all went well and the string is valid, FALSE otherwise 00950 Purpose: Convert a number in MpValue to a string representation of that 00951 number in the given units. ie converting 72000 millipoints to inches 00952 would give the string '1in'. 00953 If DecimalPlaces = -1 then use the default preference value which the user 00954 has specified. 00955 See Also: DocUnitList 00956 00957 ********************************************************************************************/ 00958 00959 BOOL Convert::MillipointsToString( double MpValue, UnitType TheUnit, StringBase* OutputString, 00960 INT32 DecimalPlaces) 00961 { 00962 ERROR2IF(OutputString == NULL,FALSE,"MillipointsToString NULL output string supplied"); 00963 // Decimal places will be -1 if the default number is to be used. 00964 00965 double Value = 1.0; 00966 String_32 Specifier; 00967 TCHAR p[256], format[256], dpformat[256]; 00968 00969 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList(); 00970 DocUnitList FactoryDefUnits; 00971 if(pDocUnitList==NULL) 00972 { 00973 // certain classes (eg OpDescriptors) may want to call this function to set 00974 // values in controls after they have been read in by the bars/dialogs etc... 00975 // However at that point (Document::GetCurrent() == NULL) so you can't get 00976 // a DocUnitList from the current doc. Hence create our own default units 00977 FactoryDefUnits.Init(); 00978 FactoryDefUnits.MakeDefaultUnits(); 00979 pDocUnitList = &FactoryDefUnits; 00980 } 00981 00982 Unit* pUnit = pDocUnitList->FindUnit(TheUnit); 00983 00984 // Find out how many Units MpValue represents 00985 Value = MpValue / pUnit->GetMillipoints(); 00986 00987 // Get the specifier of the units we're in 00988 Specifier = pUnit->GetSpecifier(); 00989 00990 // check if we want the default number of decimal places 00991 if (DecimalPlaces == -1) DecimalPlaces = NumDecimalPlaces; 00992 00993 //_stprintf(dpformat,"%%.%df",DecimalPlaces); // Makes "%.xf" where x is num dp 00994 // Makes the output form "%.xf" where x is num dp. 00995 // %g instead of %f gives leading zero supression but then requires number significant 00996 // figures rather than number of decimal places. 00997 camSnprintf( dpformat, 256, TEXT("%%.%df"), DecimalPlaces) ; 00998 00999 // Create the string to stick in an editable field (or wherever you like) 01000 if (pUnit->IsPrefix()) 01001 { 01002 // Prefix units so show units followed by value 01003 camSnprintf( format, 256, _T("%%s%s"), (LPCTSTR) dpformat ); // ie. %s %.3f 01004 camSnprintf( p, 256, format, (LPCTSTR)Specifier, (double)Value ); // uses FP 01005 *OutputString = p; 01006 // Look for all zeros after decimal point and if so then remove 01007 //StripTrailingZeros(OutputString); 01008 } 01009 else 01010 { 01011 // Suffix units so show value followed by units 01012 camSnprintf( p, 256, dpformat, (double)Value ); // uses FP 01013 *OutputString = p; 01014 01015 // Look for all zeros after decimal point and if so then remove 01016 StripTrailingZeros(OutputString); 01017 01018 // Finally, add in the unit specifier 01019 *OutputString += Specifier; 01020 } 01021 01022 01023 // Extra bodge required so that if the user has specified display values using 01024 // a non full stop to show decimal points then we must replace the point that 01025 // is present by the specified character. 01026 if (DecimalPoint != '.') 01027 { 01028 ReplaceDecimalPoint(OutputString); 01029 } 01030 01031 return TRUE; 01032 } 01033 01034 01035 /******************************************************************************************** 01036 01037 > static BOOL Convert::LongToString( INT32 Number, StringBase* OutputString ) 01038 01039 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01040 Created: 17/9/93 01041 Inputs: Number - The number you want turning into a string 01042 Outputs: OutputString - The string that gets created 01043 Returns: TRUE if the conversion worked, false otherwise 01044 Purpose: Converts a INT32 to a its string equivalent. 01045 SeeAlso: StringToLong 01046 01047 ********************************************************************************************/ 01048 01049 BOOL Convert::LongToString( INT32 Number, StringBase* OutputString ) 01050 { 01051 OutputString -> Empty(); 01052 01053 if (Number < 0) 01054 { 01055 TCHAR buff[2] ; 01056 buff[0] = TEXT('-'); 01057 buff[1] = TEXT('\0'); 01058 01059 *OutputString += String_8(buff); 01060 Number = -Number; 01061 01062 } 01063 01064 NumberToString( Number, OutputString ); 01065 01066 return TRUE; 01067 } 01068 01069 /******************************************************************************************** 01070 01071 > static BOOL Convert::DoubleToString( double Number, StringBase* OutputString, INT32 DecimalPlaces ) 01072 01073 Author: Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com> 01074 Created: 16/12/94 01075 Inputs: Number - The number you want turning into a string 01076 DecimalPlaces - The number of Decimal places required (0-3). This defaults to 01077 -1 which means use the default preference value. Don't override it unless 01078 absolutely necessary. 01079 01080 Outputs: OutputString - The string that gets created 01081 Returns: TRUE if the conversion worked, false otherwise 01082 Purpose: Converts a double to a its string equivalent. 01083 SeeAlso: StringToDouble 01084 01085 This routine is a bit of a bodge 01086 01087 ********************************************************************************************/ 01088 01089 BOOL Convert::DoubleToString( double Number, StringBase* OutputString, INT32 DecimalPlaces /* =-1 */ ) 01090 { 01091 // Generate the output string in a simple char array 01092 TCHAR dpformat[32]; 01093 TCHAR TempString[32]; 01094 01095 // Use the default/preference or desired number of decimal places 01096 if (DecimalPlaces < 0) 01097 DecimalPlaces = (INT32) NumDecimalPlaces; // Use the preference value 01098 01099 camSnprintf( dpformat, 32, _T("%%.%df"), (INT32) DecimalPlaces); // make %.xf formatting string 01100 camSnprintf( TempString, 32, dpformat, (double)Number ); // uses FP 01101 01102 *OutputString = TempString; // Copy the resulting string into the String 01103 01104 // Look for all zeros after decimal point and if so then remove 01105 StripTrailingZeros(OutputString); 01106 01107 // Extra bodge required so that if the user has specified display values using 01108 // a non full stop to show decimal points then we must replace the point that 01109 // is present by the specified character. 01110 if (DecimalPoint != '.') 01111 { 01112 ReplaceDecimalPoint(OutputString); 01113 } 01114 return TRUE; 01115 } 01116 01117 01118 /******************************************************************************************** 01119 01120 > static BOOL Convert::StringToLong( StringBase* InputString, INT32* Number ) 01121 01122 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01123 Created: 17/9/93 01124 Inputs: InputString - The string that you want turning into a number 01125 Outputs: Number - The number you want turning into a string 01126 Returns: TRUE if the conversion worked, false otherwise 01127 Purpose: Converts a string into its INT32 equivalent 01128 SeeAlso: LongToString 01129 01130 ********************************************************************************************/ 01131 01132 BOOL Convert::StringToLong( const StringBase &InputString, INT32* pNumber) 01133 { 01134 // Get a pointer version of the string 01135 const TCHAR* pMyString = (const TCHAR*)InputString; 01136 INT32 nLength = InputString.Length(); 01137 INT32 nPos = 0; 01138 01139 // Check for a minus sign - added for DBCS 01140 BOOL fIsNegative = FALSE; 01141 if (pMyString[nPos] == TEXT('-') ) // if (pMyString[Pos] == TEXT('-')) 01142 { 01143 fIsNegative = TRUE; 01144 nPos++; 01145 if (nPos >= nLength) return 0; 01146 } 01147 01148 // Get the actual number 01149 INT32 nTotal = 0; 01150 while (nPos < nLength && StringBase::IsNumeric(pMyString[nPos])) 01151 { 01152 nTotal = (nTotal * 10) + pMyString[nPos] - TEXT('0'); 01153 nPos++; 01154 } 01155 01156 // If we have not read in the whole string, then it was not valid 01157 if (nPos < nLength && !StringBase::IsSpace(pMyString[nPos])) return FALSE; 01158 01159 // If the number started with a minus sign, then make sure it is negative 01160 if (fIsNegative) nTotal = -nTotal; 01161 01162 *pNumber = nTotal; 01163 return TRUE; 01164 } 01165 01166 /******************************************************************************************** 01167 01168 > static BOOL Convert::StringToDouble( StringBase* InputString, double * Number ) 01169 01170 Author: Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com> 01171 Created: 16/12/94 01172 Inputs: InputString - The string that you want turning into a double 01173 Outputs: Number - The number you want turning into a string 01174 Returns: TRUE if the conversion worked, false otherwise 01175 Purpose: Converts a string into its double equivalent 01176 SeeAlso: DoubleToString 01177 01178 Used to be a bodge as atof() doesn't work in unicode but converted to use 01179 the other functions which should do it properly. 01180 01181 ********************************************************************************************/ 01182 01183 BOOL Convert::StringToDouble( const StringBase &InputString, double * Number ) 01184 { 01185 //#if UNICODE 01186 //#error "I'm screwed! atof() doesn't work for UNICODE" 01187 //#else 01188 // *Number = atof((char *)*InputString); 01189 // return(TRUE); 01190 //#endif 01191 01192 // Cannot use atof as does not cope with a non-decimal point character which 01193 // the user may be specifying so use our form of atof. 01194 // atof will also allow say 26.98mm where we should really be erroring. 01195 // ReadNumber ignores everything after a dodgy decimal point which is not correct. 01196 // StringToComponents will include units as well. We do not want this part so ignore it. 01197 UnitType Units; 01198 BOOL ok = StringToComponents(InputString,Number,&Units); 01199 01200 // Check if units are NOTYPE and if not then return failure. 01201 if (Units != NOTYPE) 01202 return FALSE; 01203 01204 return ok; 01205 } 01206 01207 01208 #define MIN_MILLIPOINT_VAL (-2147483648.0) // Min signed 32 bit val - 0x80000000 01209 #define MAX_MILLIPOINT_VAL ( 2147483647.0) // Max signed 32 bit val - 0x7fffffff 01210 01211 /******************************************************************************************** 01212 01213 > static BOOL Convert::ConvertDoubleToMillipoint(double Value,MILLIPOINT* pResult) 01214 01215 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01216 Created: 6/7/94 01217 Inputs: Value = the fp value to convert 01218 Outputs: pResult = the MILLIPOINT var to place the result in 01219 Returns: TRUE if the conversion was OK 01220 FALSE if the conversion caused an overflow error 01221 Purpose: Converts a double to a MILLIPOINT, checking first whether such a conversion 01222 is possible. 01223 It returns FALSE if Value is beyond the limits of a signed 32 bit integer. 01224 SeeAlso: ConvertMillipointToDouble 01225 01226 ********************************************************************************************/ 01227 01228 BOOL Convert::ConvertDoubleToMillipoint(double Value,MILLIPOINT* pResult) 01229 { 01230 Value += 0.5; // Round up the value 01231 01232 if ((Value < MIN_MILLIPOINT_VAL) || (Value > MAX_MILLIPOINT_VAL)) 01233 return FALSE; 01234 01235 *pResult = (MILLIPOINT)Value; 01236 return TRUE; 01237 } 01238 01239 /******************************************************************************************** 01240 01241 > static void Convert::ConvertMillipointToDouble(MILLIPOINT Value,double* pResult) 01242 01243 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01244 Created: 6/7/94 01245 Inputs: Value = the MILLIPOINT value to convert 01246 Outputs: pResult = the double var to place the result in 01247 Returns: - 01248 Purpose: Converts a MILLIPOINT to a double. 01249 At the moment, this function just does a simple cast. 01250 I've only put it in because I did the sister function ConvertDoubleToMillipoint 01251 SeeAlso: ConvertDoubleToMillipoint 01252 01253 ********************************************************************************************/ 01254 01255 void Convert::ConvertMillipointToDouble(MILLIPOINT Value,double* pResult) 01256 { 01257 *pResult = (double)Value; 01258 } 01259 01260 01261 /****************************************************************************************** 01262 01263 > static UINT32 Convert::StringToBytes(String_256 *pStr, BOOL *Valid) 01264 01265 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 01266 Created: 20/1/95 01267 Inputs: pStr - pointer to all manner of memory amount specifying strings 01268 such as "1024k", "1024 bytes", "1024", "1048576", "1Mb". 01269 (NB - The above will all return 1024 (and Valid == TRUE)). 01270 Outputs: Valid - used to flag a valid result. Invalid results will return 0 and 01271 flag this variable to FALSE. Any non-numerically starting 01272 strings will cause this invalid state. Leading spaces shouldn't 01273 pose a problem... 01274 Returns: Number of bytes described by input string, so "1k" would produce 1024... 01275 Purpose: Takes a string with a textual description of an amount of memory, and 01276 returns the amount of bytes described by the string. 01277 Errors: At present we only use simple string matching, so "100 Tera-bytes" will 01278 return 100, as Tera is not supported and the bytes section is matched. 01279 Also "200 trams" will return 200*1024*1024, as the 'm' of trams is matched 01280 as flagging a mega-byte. 01281 SeeAlso: - 01282 01283 ******************************************************************************************/ 01284 01285 UINT32 Convert::StringToBytes( const StringBase &Str, BOOL *Valid) 01286 { 01287 // Set up bad return value until we are fairly happy with the string 01288 *Valid = FALSE; 01289 01290 //changed char to TCHAR for DBCS 01291 const TCHAR *CharStr = (const TCHAR *)Str; 01292 01293 double Number = 0.0; 01294 INT32 Pos = 0; 01295 UINT32 ret = 0; 01296 // Try and read the value in using are routine 01297 // Cannot use atof as does not cope with non-standard decimal point and thousand 01298 // separator characters. 01299 // UINT32 ret=_ttoi(CharStr); // Rip the numbers from the start 01300 BOOL ok = ReadNumber(Str, &Pos, &Number); 01301 if (!ok) return 0; // bad number so return invalid 01302 01303 // If negative then return invalid and zero. 01304 if (Number < 0) return 0; 01305 // If bigger than what can be held in a UINT32 then return the maximum and FALSE. 01306 if (Number > (double)UINT32_MAX) return UINT32_MAX; 01307 01308 // We have what looks like a fairly valid number so set return flag True; 01309 *Valid = TRUE; 01310 01311 // If value is zero then return with no more checking as not relevent 01312 if (Number == 0) return (0); 01313 01314 if ( cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_SMALL_K)) /*"k"*/) 01315 || cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_LARGE_K)) /*"K"*/) ) 01316 { 01317 // Check if K or K is in the string and if so multiply by 1024 01318 Number = Number*1024; // Kilobyte value 01319 } 01320 else if ( cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_SMALL_M)) /*"m"*/) 01321 || cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_LARGE_M)) /*"M"*/) ) 01322 { 01323 // Check if M or m is in the string and if so multiply by 1024 by 1024 01324 Number = Number*1024*1024; // Megabyte value 01325 } 01326 else if ( cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_SMALL_G)) /*"g"*/) 01327 || cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_LARGE_G)) /*"G"*/) ) 01328 { 01329 // Check if G or g is in the string and if so multiply by 1024 by 1024 by 1024 01330 Number = Number*1024*1024*1024; // Gigabyte value 01331 } 01332 else if ( cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_SMALL_BYTE)) /*"byte"*/) 01333 || cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_MEDIUM_BYTE)) /*"Byte"*/) 01334 || cc_lstrstr(CharStr, (TCHAR *)String_16(_R(IDS_CONVERT_LARGE_BYTE)) /*"BYTE"*/) ) 01335 { 01336 // Check if byte or variation of specified in which case just return the value 01337 // Number = Number; // straight byte value 01338 } 01339 // if none of the above then assume value is in bytes and hence do nothing 01340 01341 // If bigger than what can be held in a UINT32 then return the maximum and FALSE. 01342 if (Number > (double)UINT32_MAX) return UINT32_MAX; 01343 01344 // We just want the interger part of the number specified as fractional parts are non-valid 01345 ret = (UINT32)Number; 01346 TRACEUSER( "Neville", _T("%s -> %d\n"), (char *)CharStr, ret ); 01347 01348 return ret; 01349 } 01350 01351 /******************************************************************************************* 01352 > static void Convert::BytesToString(StringBase* String, UINT32 Bytes); 01353 01354 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 01355 Created: 26th August 1994 01356 Inputs: String - The string to store the formatted memory size in. The 01357 existing contents of the string are overwritten. 01358 Bytes - The number of bytes which to format and store. 01359 Returns: - 01360 Purpose: Converts the Bytes number into a string of the following format: 01361 Bytes = 0 "0 bytes" 01362 Bytes = 1 "1 byte" 01363 2 <= Bytes < 4096 "<n> bytes" 01364 4096 <= Bytes < 4M "<n/1024> K" 01365 4M <= Bytes "<n/1Meg> M" 01366 *******************************************************************************************/ 01367 01368 BOOL Convert::BytesToString(StringBase* pString, UINT32 Bytes) 01369 { 01370 ERROR2IF(pString==NULL, FALSE, "NULL output pointer"); 01371 ERROR3IF(Bytes<0, "The number of bytes must be positive"); 01372 if(Bytes<0) Bytes = 0-Bytes; 01373 pString->Empty(); 01374 01375 INT32 Number = 0; 01376 UINT32 Resource = 0; 01377 String_16 Working; 01378 String_8 ThousandsSepStr; 01379 ThousandsSepStr += (TCHAR)ThousandSep; 01380 01381 01382 // Work out which resource string to use depending on the number of bytes 01383 if (Bytes == 1) 01384 { 01385 Number = 1; 01386 Resource = _R(IDS_MEMORYFORMAT_BYTE); 01387 } 01388 else 01389 { 01390 if (Bytes < 4096) 01391 { 01392 Number = Bytes; 01393 Resource = _R(IDS_MEMORYFORMAT_BYTES); 01394 } 01395 else 01396 { 01397 if (Bytes < (4096*1024)) 01398 { 01399 Number = Bytes/1024; 01400 Resource = _R(IDS_MEMORYFORMAT_KILO); 01401 } 01402 else 01403 { 01404 Number = Bytes/(1024*1024); 01405 Resource = _R(IDS_MEMORYFORMAT_MEGA); 01406 } 01407 } 01408 } 01409 01410 // Put the number into a string and add thousand seperator 01411 Working._MakeMsg( wxT("#1%lu"), Number ); 01412 if (Working.Length() > 3) 01413 Working.Insert(ThousandsSepStr, Working.Length()-3); 01414 01415 // put the number string into the string resource 01416 pString->MakeMsg(Resource, &Working); 01417 01418 return TRUE; 01419 } 01420 01421 01422 01423 //------------------------------------------------- 01424 //------------------------------------------------- 01425 //------------------------------------------------- 01426 //------------------------------------------------- 01427 01428 01429 /******************************************************************************************** 01430 01431 > static BOOL DimScale::Init() 01432 01433 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01434 Created: 22/6/94 01435 Inputs: - 01436 Outputs: - 01437 Returns: TRUE if successfully initialised 01438 Purpose: Initialises this class. Must be called before any other function 01439 in this class 01440 SeeAlso: - 01441 01442 ********************************************************************************************/ 01443 01444 BOOL DimScale::Init() 01445 { 01446 BOOL ok; 01447 01448 pDefaultDimScale = new DimScale; 01449 ok = (pDefaultDimScale != NULL); 01450 if (ok) pDefaultDimScale->SetActiveState(FALSE); 01451 01452 return ok; 01453 } 01454 01455 /******************************************************************************************** 01456 01457 > static void DimScale::Deinit() 01458 01459 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01460 Created: 28/6/94 01461 Inputs: - 01462 Outputs: - 01463 Returns: - 01464 Purpose: Initialises this class. Must be called before any other function 01465 in this class 01466 SeeAlso: - 01467 01468 ********************************************************************************************/ 01469 01470 void DimScale::Deinit() 01471 { 01472 if (pDefaultDimScale != NULL) 01473 { 01474 delete pDefaultDimScale; 01475 pDefaultDimScale = NULL; 01476 } 01477 } 01478 01479 /******************************************************************************************** 01480 01481 > DimScale::DimScale() 01482 01483 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01484 Created: 14/6/94 01485 Inputs: - 01486 Outputs: - 01487 Returns: - 01488 Purpose: Constructor 01489 SeeAlso: - 01490 01491 ********************************************************************************************/ 01492 01493 DimScale::DimScale() 01494 { 01495 // Set up some useful defaults 01496 Active = FALSE; 01497 DrawingScaleStr = _R(IDS_CONVERT_ONE_CM); //"1 cm"; 01498 RealScaleStr = _R(IDS_CONVERT_ONE_MI); //"1 mi"; 01499 ScaleFactor = MI_MP_VAL / CM_MP_VAL; 01500 } 01501 01502 /******************************************************************************************** 01503 > UnitType DimScale::GetUnits() 01504 01505 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01506 Created: 18/10/95 01507 Returns: Scale units if scaling active else page units (NOTYPE for error) 01508 Purpose: For getting hold of those pesky units 01509 ********************************************************************************************/ 01510 01511 UnitType DimScale::GetUnits() 01512 { 01513 UnitType Units=GetScaleUnits(); 01514 if (Units==NOTYPE) 01515 { 01516 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList(); 01517 ERROR2IF(pDocUnitList==NULL,NOTYPE,"DimScale::GetUnits() - pDocUnitList==NULL"); 01518 Units = pDocUnitList->GetPageUnits(); 01519 } 01520 01521 return Units; 01522 } 01523 01524 01525 /******************************************************************************************** 01526 > UnitType DimScale::GetScaleUnits() 01527 01528 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01529 Created: 18/10/95 01530 Returns: Scale units if active else NOTYPE (NOTYPE for error) 01531 Purpose: For getting hold of those pesky scale units 01532 ********************************************************************************************/ 01533 01534 UnitType DimScale::GetScaleUnits() 01535 { 01536 if (IsActive()==FALSE) 01537 return NOTYPE; 01538 01539 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList(); 01540 ERROR2IF(pDocUnitList==NULL,NOTYPE,"DimScale::GetScaleUnits() - pDocUnitList==NULL"); 01541 01542 UnitType ScaleUnits = pDocUnitList->GetScaleUnits(); 01543 if (ScaleUnits==AUTOMATIC) 01544 { 01545 double dummy = 1.0; 01546 BOOL ok = Convert::StringToComponents( RealScaleStr,&dummy,&ScaleUnits); 01547 if (!ok || ScaleUnits==NOTYPE) 01548 ScaleUnits = pDocUnitList->GetPageUnits(); 01549 } 01550 01551 return ScaleUnits; 01552 } 01553 01554 01555 /******************************************************************************************** 01556 01557 > void DimScale::SetActiveState(BOOL State) 01558 01559 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01560 Created: 14/6/94 01561 Inputs: State = Boolean value of activity 01562 Outputs: - 01563 Returns: - 01564 Purpose: Used to set the active state of this dimension scaling object. 01565 When inactive, no scaling is performed 01566 SeeAlso: - 01567 01568 ********************************************************************************************/ 01569 01570 void DimScale::SetActiveState(BOOL State) 01571 { 01572 Active = State; 01573 } 01574 01575 /******************************************************************************************** 01576 01577 > BOOL DimScale::IsActive() 01578 01579 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01580 Created: 14/6/94 01581 Inputs: - 01582 Outputs: - 01583 Returns: The active state of this object 01584 Purpose: Interogate the active state of this object 01585 SeeAlso: - 01586 01587 ********************************************************************************************/ 01588 01589 BOOL DimScale::IsActive() 01590 { 01591 return (Active); 01592 } 01593 01594 /************************************************************************************** 01595 > String_32 DimScale::GetDrawingScaleStr() 01596 01597 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01598 Created: 22/6/94 01599 Inputs: - 01600 Returns: The string that represents the document scale 01601 Purpose: This is the string that the user has typed into the "Drawing scale" 01602 editable field of the scale factor dialog 01603 01604 ***************************************************************************************/ 01605 01606 String_32 DimScale::GetDrawingScaleStr() 01607 { 01608 return DrawingScaleStr; 01609 } 01610 01611 01612 /************************************************************************************** 01613 > void DimScale::SetDrawingScaleStr(String_32& NewStr) 01614 01615 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01616 Created: 22/6/94 01617 Inputs: Reference to the new drawing scale string 01618 Returns: TRUE if string represents a good value, FALSE otherwise. 01619 Purpose: Allows the setting of a new string that is to be used as the drawing 01620 scaling factor. This has usually been typed in by the user into the 01621 "Drawing scale" editable field of the scale factor dialog. The string 01622 is attempted to be converted to a value and the value checked. If it 01623 is ok then TRUE is returned otherwise FALSE is returned. 01624 01625 This ***MUST *** not ERROR2 or set an error on bad values as the scale 01626 options tab code tries to produce a nice error for the user when they 01627 have entered incorrect values rather than completely incomprehensible 01628 internal errors. 01629 SeeAlso: ScaleTab::CommitSection; Document::ImportViewInfo; 01630 01631 ***************************************************************************************/ 01632 01633 BOOL DimScale::SetDrawingScaleStr(String_32& NewStr) 01634 { 01635 double Scale = 1.0; 01636 BOOL ok = TRUE; 01637 //changed char to TCHAR for DBCS 01638 // TCHAR* p = DrawingScaleStr; // for debugging purposes 01639 01640 ok = ConvertToDouble( NewStr,&Scale); 01641 if (!ok) 01642 return FALSE; // let the caller decide what error to show! 01643 //ERROR2IF(!ok,FALSE,"DrawingScaleStr is bad!"); 01644 01645 // Check that the converted value is a real positive value and certainly not zero! 01646 if (Scale <= 0) 01647 return FALSE; 01648 01649 // Only if everything went ok will we set the DrawingScaleStr to be the newly 01650 // specified value. 01651 if (ok) 01652 DrawingScaleStr = NewStr; 01653 01654 return TRUE; 01655 } 01656 01657 01658 /************************************************************************************** 01659 > String_32 DimScale::GetRealScaleStr() 01660 01661 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01662 Created: 22/6/94 01663 Inputs: - 01664 Returns: The string that represents the document scale 01665 Purpose: This is the string that the user has typed into the "Real scale" editable 01666 field of the scale factor dialog 01667 01668 ***************************************************************************************/ 01669 01670 String_32 DimScale::GetRealScaleStr() 01671 { 01672 return RealScaleStr; 01673 } 01674 01675 01676 /************************************************************************************** 01677 > void DimScale::SetRealScaleStr(String_32& NewStr) 01678 01679 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01680 Created: 22/6/94 01681 Inputs: Reference to the new Real scale string 01682 Returns: TRUE if string represents a good value, FALSE otherwise. 01683 Purpose: Allows the setting of a new string that is to be used as the real 01684 scaling factor. This has usually been typed in by the user into the 01685 "Real scale" editable field of the scale factor dialog. The string 01686 is attempted to be converted to a value and the value checked. If it 01687 is ok then TRUE is ereturned otherwise FALSE is returned. 01688 01689 This ***MUST *** not ERROR2 or set an error on bad values as the scale 01690 options tab code tries to produce a nice error for the user when they 01691 have entered incorrect values rather than completely incomprehensible 01692 internal errors. 01693 SeeAlso: ScaleTab::CommitSection; Document::ImportViewInfo; 01694 01695 ***************************************************************************************/ 01696 01697 BOOL DimScale::SetRealScaleStr(String_32& NewStr) 01698 { 01699 double Scale = 1.0; 01700 BOOL ok; 01701 //From char to TCHAR for DBCS 01702 // TCHAR* p = RealScaleStr; // for debugging purposes 01703 01704 ok = ConvertToDouble( NewStr,&Scale); 01705 if (!ok) 01706 return FALSE; // let the caller decide what error to show! 01707 //ERROR2IF(!ok,FALSE,"RealScaleStr is bad!"); VERY BAD!!!! 01708 01709 // Check that the converted value is a real positive value and certainly not zero! 01710 if (Scale <= 0) 01711 return FALSE; 01712 01713 // Only if everything went ok will we set the DrawingScaleStr to be the newly 01714 // specified value. 01715 if (ok) 01716 RealScaleStr = NewStr; 01717 01718 return TRUE; 01719 } 01720 01721 /************************************************************************************** 01722 > BOOL DimScale::SetScaleFactor() 01723 01724 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01725 Created: 22/6/94 01726 Inputs: - 01727 Returns: TRUE if successfully converted and a new scaling factor set, FALSE otherwise. 01728 Purpose: Reads the DrawingScaleStr and RealScaleStr, which should specify the drawing 01729 and real scaling factors, and calculates the new scale factor from these. 01730 If either are negative or zero then it will return FALSE and no new scaling 01731 factor is set. 01732 01733 This ***MUST *** not ERROR2 or set an error on bad values as the scale 01734 options tab code tries to produce a nice error for the user when they 01735 have entered incorrect values rather than completely incomprehensible 01736 internal errors. 01737 SeeAlso: ScaleTab::CommitSection; Document::ImportViewInfo; 01738 01739 ***************************************************************************************/ 01740 01741 BOOL DimScale::SetScaleFactor() 01742 { 01743 double RealScale = 1.0; 01744 double DrawingScale = 1.0; 01745 BOOL ok = TRUE; 01746 //char to TCHAR for DBCS 01747 // TCHAR* pD = DrawingScaleStr; // for debugging purposes 01748 // TCHAR* pR = RealScaleStr; // for debugging purposes 01749 01750 RealScale = Convert::StringToDouble( RealScaleStr,GetUnits(),&ok); 01751 if (!ok) 01752 return FALSE; // let the caller decide what error to show! 01753 //ERROR2IF(!ok,FALSE,"RealScaleStr is bad!"); 01754 01755 // Check that the converted value is a real positive value and certainly not zero! 01756 if (RealScale <= 0) 01757 return FALSE; 01758 01759 DrawingScale = Convert::StringToDouble( DrawingScaleStr,GetUnits(),&ok); 01760 if (!ok) 01761 return FALSE; // let the caller decide what error to show! 01762 //ERROR2IF(!ok,FALSE,"DrawingScaleStr is bad!"); 01763 01764 // Check that we are not going to get a division by zero error 01765 if (DrawingScale != 0) 01766 ScaleFactor = RealScale / DrawingScale; 01767 else 01768 return FALSE; 01769 01770 return TRUE; 01771 } 01772 01773 /******************************************************************************************** 01774 > BOOL DimScale::ConvertToUnits(double MpValue, String_256* pStr, BOOL UnitSpecifier=TRUE, 01775 INT32 dp=-1, UnitType units=NOTYPE, BOOL bSquare = FALSE) 01776 01777 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01778 Created: 14/6/94 01779 Inputs: MpValue = A value in Camelot's internal millipoints 01780 pStr = Ptr to a string to store the converted MpValue 01781 UnitSpecifier - If TRUE the unit specifier is included 01782 e.g. "1.27 cm" or "1.27" for TRUE or FALSE respectively 01783 dp - number of decimal places (-1 means use system default) 01784 (100+n means use n significant figures) 01785 units - type of units to convert to 01786 bSquare - MpValue measures an area 01787 Returns: TRUE if successfully converted, FALSE otherwise 01788 Purpose: This converts a millipoint value into a string representation that reflects 01789 the dimension scaling specified in this object. 01790 If this object represented a scaling of 1 mile = 1 inch, then if MpValue = 72000 01791 pStr would contain "1 mi" on exit. 01792 Errors: dp<0 01793 ********************************************************************************************/ 01794 01795 BOOL DimScale::ConvertToUnits(double MpValue, String_256* pStr, BOOL UnitSpecifier, 01796 INT32 dp, UnitType units, BOOL bSquare) 01797 { 01798 ERROR2IF(pStr == NULL, FALSE,"DimScale::ConvertToUnits() result string = Null"); 01799 01800 // If dp is -1 then use the default preference value specified by the user. 01801 if (dp == -1) 01802 dp = Convert::GetNumberDecimalPlaces(); // Use the default preference value 01803 else if (dp == 100) 01804 dp = 100 + Convert::GetNumberDecimalPlaces(); // Use the default preference value 01805 01806 // If dp is anything else i.e. negative then make zero but warn debug users as bad value. 01807 if (dp < 0) 01808 { 01809 ERROR3("DimScale::ConvertToUnits() - dp<0"); 01810 dp = 0; // Use no decimal places 01811 } 01812 01813 double ScaledValue = 1.0; 01814 double sf = 1.0; 01815 String_32 Specifier; 01816 TCHAR p[256]; 01817 01818 // Get the current unit list from the document and the the current scale units 01819 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList(); 01820 // ERROR2IF(pDocUnitList == NULL, FALSE,"DimScale::ConvertToUnits() No current document units"); 01821 if (pDocUnitList == NULL) 01822 { 01823 TRACE( wxT("No Unit list - if this not an OLE paste, PANIC!!!\n") ); 01824 return FALSE; 01825 } 01826 01827 if (units==NOTYPE) 01828 units = GetUnits(); 01829 Unit* pScaleUnit = pDocUnitList->FindUnit(units); 01830 ERROR2IF(pScaleUnit == NULL, FALSE,"DimScale::ConvertToUnits() Null scale units"); 01831 01832 // If active, use the scale factor, otherwise use 1.0 (i.e. no scaling) 01833 if (Active) 01834 { 01835 sf = ScaleFactor; 01836 if (bSquare) 01837 sf *= ScaleFactor; 01838 } 01839 else 01840 sf = 1.0; 01841 01842 // Find out how many Units MpValue represents, avoiding div by zero's 01843 double NumMpInUnit = pScaleUnit->GetMillipoints(); 01844 if (NumMpInUnit != 0) 01845 { 01846 ScaledValue = MpValue*sf / NumMpInUnit; 01847 if (bSquare) 01848 ScaledValue = ScaledValue / NumMpInUnit; 01849 } 01850 else 01851 ScaledValue = 0; 01852 01855 // 01856 // [Phil 26/09/2005] 01857 // This kludge is retained only for back-compatibility with X1 - OpScale2Trans has 01858 // been removed 01859 if( ( NumMpInUnit <= ((double)MM_MP_VAL + (double)MP_MP_VAL)) && ( dp > 1 ) ) 01860 dp = 1; 01861 01862 // If the value to 2dp is 1.00, use the singular unit name 01863 // (Only applicable when ExpandUnitName is TRUE) 01864 // Plural = (abs((INT32)((ScaledValue+0.005)*100.0)) != 100); 01865 01866 // Get the specifier of the units we're in 01867 Specifier = pScaleUnit->GetSpecifier(); 01868 01869 // Create the string to stick in an editable field (or wherever you like) 01870 if (UnitSpecifier) 01871 { 01872 if (dp<=100) 01873 { 01874 if (pScaleUnit->IsPrefix()) 01875 { 01876 // Prefix units required so print them first followed by the number 01877 camSnprintf( p, 256, _T("%s%.*f"), (LPCTSTR) Specifier, (INT32) dp, (double)ScaledValue ); // uses * & FP 01878 01879 // Look for all zeros after decimal point and if so then remove 01880 *pStr = p; 01881 Convert::StripTrailingZeros(pStr); 01882 } 01883 else 01884 { 01885 // Suffix units required so print number followed by units 01886 // Used to do this in one go but makes life more difficult on the trailing 01887 // zero supression front. 01888 //_stprintf(p,"%.*f%s",dp,ScaledValue,(char*)Specifier); 01889 camSnprintf( p, 256, _T("%.*f") , (INT32) dp, (double) ScaledValue ); // uses * & FP 01890 01891 // Look for all zeros after decimal point and if so then remove 01892 *pStr = p; 01893 Convert::StripTrailingZeros(pStr); 01894 01895 // And finally add the units in 01896 *pStr += Specifier; 01897 } 01898 } 01899 else 01900 { 01901 if (pScaleUnit->IsPrefix()) 01902 { 01903 // Prefix units required so print them first followed by the number 01904 camSnprintf( p, 256, _T("%s%.*g"), (LPCTSTR) Specifier, (INT32) dp-100, (double) ScaledValue); 01905 01906 // Look for all zeros after decimal point and if so then remove 01907 *pStr = p; 01908 } 01909 else 01910 { 01911 // Suffix units required so print number followed by units 01912 camSnprintf( p, 256, _T("%.*g%s"), (INT32) dp-100, (double)ScaledValue, (LPCTSTR)Specifier ); 01913 01914 // Look for all zeros after decimal point and if so then remove 01915 *pStr = p; 01916 } 01917 } 01918 } 01919 else 01920 { 01921 if (dp<=100) 01922 { 01923 // No units so just output the value 01924 camSnprintf( p, 256, wxT("%.*f"), (INT32) dp, (double) ScaledValue); // uses * & FP 01925 01926 // Look for all zeros after decimal point and if so then remove 01927 *pStr = p; 01928 Convert::StripTrailingZeros(pStr); 01929 } 01930 else 01931 { 01932 // No units so just output the value 01933 camSnprintf( p, 256, wxT("%.*g"), (INT32) dp-100, (double)ScaledValue ); 01934 01935 // Look for all zeros after decimal point and if so then remove 01936 *pStr = p; 01937 } 01938 } 01939 01940 //*pStr = p; 01941 01942 // Extra bodge required so that if the user has specified display values using 01943 // a non full stop to show decimal points then we must replace the point that 01944 // is present by the specified character. 01945 if (Convert::GetDecimalPointChar() != '.') 01946 { 01947 Convert::ReplaceDecimalPoint(pStr); 01948 } 01949 01950 return TRUE; 01951 } 01952 01953 /******************************************************************************************** 01954 01955 > BOOL DimScale::ConvertToDouble(StringBase* pStr,double* pResult) 01956 01957 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01958 Created: 22/6/94 01959 Inputs: pStr = Ptr to a string containing value to convert 01960 Outputs: pResult = Ptr to the resultant millipoint value in fp form. 01961 Returns: TRUE if successfully converted, FALSE otherwise 01962 Purpose: This takes a string of the form "45.3 km" and converts it to the correctly 01963 scaled millipoint value. E.g if 1 km = 2 cm then "45.3 km" would give 01964 (45.3 * 2 * 28346.52715) millipoints, where 28346.52715 is the num millipoints 01965 in one centimetre. 01966 SeeAlso: - 01967 01968 ********************************************************************************************/ 01969 01970 BOOL DimScale::ConvertToDouble(const StringBase &str,double* pResult) 01971 { 01972 double Result=72000.0; // Provide something useful in case BOOL result is ignored 01973 BOOL ok; 01974 01975 // Convert the string into its component parts 01976 // Use scale units if units are NOT specified in the string 01977 Result = Convert::StringToDouble(str,GetUnits(),&ok); 01978 01979 if (ok) 01980 { 01981 // Only scale down if this object is active 01982 if (Active) 01983 Result /= ScaleFactor; // Scale result to internal millipoints 01984 } 01985 01986 *pResult = Result; // Store the result 01987 01988 return (ok); 01989 } 01990 01991 /******************************************************************************************** 01992 01993 > BOOL DimScale::ConvertToMillipoints(const StringBase& pStr, MILLIPOINT* pMpValue) 01994 01995 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01996 Created: 14/6/94 01997 Inputs: pStr = Ptr to a string containing value to convert 01998 Outputs: pMpValue= Ptr to the resultant millipoint value. 01999 Returns: TRUE if successfully converted, FALSE otherwise 02000 Purpose: This takes a string of the form "45.3 km" and converts it to the correctly 02001 scaled millipoint value. E.g if 1 km = 2 cm then "45.3 km" would give 02002 (45.3 * 2 * 28346.52715) millipoints, where 28346.52715 is the num millipoints 02003 in one centimetre. 02004 Errors: ConvertToDouble() fails 02005 result overflows 02006 02007 ********************************************************************************************/ 02008 02009 BOOL DimScale::ConvertToMillipoints(const StringBase& Str, MILLIPOINT* pMpValue) 02010 { 02011 // Set a sensible return value just in case we exit early and nobody notices 02012 // the boolean result 02013 *pMpValue = 72000; 02014 02015 double result = 1.0; 02016 if (ConvertToDouble( Str, &result) == FALSE) 02017 return FALSE; 02018 02019 result+=0.5; // round up 02020 02021 // We are going to try and convert this to a MILLIPOINT value so check that 02022 // we are not going to overflow. If we are then return FALSE and the maximum 02023 // possible value. 02024 //if (result>MaxDocCoord || result<MinDocCoord) 02025 // ERROR2(FALSE,"DimScale::ConvertToMillipoints() - overflow"); 02026 // Rather than erroring do something sensible like returning false. 02027 if (result > MaxDocCoord) 02028 { 02029 *pMpValue = MaxDocCoord; 02030 return FALSE; 02031 } 02032 02033 if (result < MinDocCoord) 02034 { 02035 *pMpValue = MinDocCoord; 02036 return FALSE; 02037 } 02038 02039 // We should be fairly happy with that result so return it to the user 02040 *pMpValue=(MILLIPOINT)result; 02041 02042 return TRUE; 02043 } 02044 02045 /************************************************************************************** 02046 > DimScale& DimScale::operator=(const DimScale& other) 02047 02048 02049 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02050 Created: 15/6/94 02051 Inputs: A reference to a constant DimScale. 02052 Returns: A reference to this. 02053 Purpose: Assignment (set equal to) operator 02054 02055 ***************************************************************************************/ 02056 02057 DimScale& DimScale::operator=(const DimScale& other) 02058 { 02059 Active = other.Active; 02060 ScaleFactor = other.ScaleFactor; 02061 DrawingScaleStr = other.DrawingScaleStr; 02062 RealScaleStr = other.RealScaleStr; 02063 02064 return *this; 02065 } 02066 02067 /************************************************************************************** 02068 > BOOL DimScale::operator==(const DimScale& other) 02069 02070 02071 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02072 Created: 15/6/94 02073 Inputs: A DimScale. 02074 Returns: TRUE if they are identical in every way 02075 Purpose: Equivalence operator 02076 02077 ***************************************************************************************/ 02078 02079 BOOL DimScale::operator==(const DimScale& other) 02080 { 02081 return ( 02082 Active == other.Active && 02083 ScaleFactor == other.ScaleFactor && 02084 DrawingScaleStr == other.DrawingScaleStr && 02085 RealScaleStr == other.RealScaleStr 02086 ); 02087 } 02088 02089 02090 02091 /************************************************************************************** 02092 > static DimScale* DimScale::GetPtrDimScale(Node* pNode) 02093 02094 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02095 Created: 15/6/94 02096 Inputs: A ptr to a node in the tree 02097 Returns: Ptr to a DimScale 02098 Purpose: Ptr to a DimScale object that can be used to scale dimension 02099 values to and from internal millipoint values. 02100 The DimScale object is taken from the node's parent Spread. 02101 If a parent spread is not found or the spread's DimScale object is 02102 inactive, the default DimScale is returned. 02103 02104 ***************************************************************************************/ 02105 02106 DimScale* DimScale::GetPtrDimScale(Node* pNode) 02107 { 02108 Spread* pSpread; 02109 DimScale* pDimScale; 02110 02111 if (!pNode->IsKindOf(CC_RUNTIME_CLASS(Spread))) 02112 pSpread = pNode->FindParentSpread(); 02113 else 02114 pSpread = (Spread*)pNode; 02115 02116 if (pSpread != NULL) 02117 { 02118 pDimScale = pSpread->GetPtrDimScale(); 02119 if (pDimScale->IsActive()) 02120 return pDimScale; 02121 } 02122 02123 return (DimScale::GetPtrDefaultDimScale()); 02124 } 02125 02126 02127 /************************************************************************************** 02128 > static DimScale* DimScale::GetPtrDefaultDimScale() 02129 02130 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02131 Created: 22/6/94 02132 Inputs: - 02133 Returns: Ptr to the default DimScale 02134 Purpose: Ptr to the default DimScale object that is returned by GetPtrDimScale 02135 if it can't find one in the tree 02136 SeeAlso: DimScale::GetPtrDimScale 02137 02138 ***************************************************************************************/ 02139 02140 DimScale* DimScale::GetPtrDefaultDimScale() 02141 { 02142 return pDefaultDimScale; 02143 } 02144 02145 02146 /************************************************************************************** 02147 > BOOL DimScale::ComponentsToMillipoint(double* pMillipoint, double Number, UnitType Units) 02148 02149 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02150 Created: 15/10/95 02151 Inputs: Number - 02152 Units - 02153 Outputs: pMillipoint - 02154 Returns: FALSE if fails 02155 Purpose: Convert a number of specified units to an accurate millipoint value 02156 Note: Unfortunately this duplicate some functionality in other routines 02157 but these functions are considered stable to change at the moment 02158 ***************************************************************************************/ 02159 02160 BOOL DimScale::ComponentsToMillipoint(double* pMillipoint, double Number, UnitType Units) 02161 { 02162 ERROR2IF(pMillipoint==NULL, FALSE,"DimScale::ComponentsToMillipoint() - pMillipoint==NULL"); 02163 ERROR2IF( Units==NOTYPE,FALSE,"DimScale::ComponentsToMillipoint() - Units==NOTYPE"); 02164 DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList(); 02165 ERROR2IF(pDocUnitList==NULL,FALSE,"DimScale::ComponentsToMillipoint() - pDocUnitList==NULL"); 02166 Unit* pUnit = pDocUnitList->FindUnit(Units); 02167 ERROR2IF(pUnit==NULL,FALSE,"DimScale::ComponentsToMillipoint() - pUnit==NULL"); 02168 02169 double Divisor = 1; 02170 if (Active) 02171 Divisor = ScaleFactor; 02172 02173 *pMillipoint = Number * pUnit->GetMillipoints() / Divisor; 02174 return TRUE; 02175 } 02176