convert.cpp

Go to the documentation of this file.
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 

Generated on Sat Nov 10 03:48:18 2007 for Camelot by  doxygen 1.4.4