units.cpp

Go to the documentation of this file.
00001 // $Id: units.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 // Implementation of the Unit class
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 //#include "units.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 //#include "markn.h"
00106 //#include "justin2.h"
00107 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "oilfiles.h"
00109 
00110 DECLARE_SOURCE("$Revision: 1282 $");
00111 CC_IMPLEMENT_DYNAMIC(Unit,ListItem)
00112 CC_IMPLEMENT_DYNAMIC(DocUnitList,List)
00113 CC_IMPLEMENT_DYNAMIC(UnitMsg,Msg)
00114 
00115 // Declare smart memory handling in Debug builds
00116 #define new CAM_DEBUG_NEW
00117 
00118 /********************************************************************************************
00119 
00120 >   Unit::Unit()
00121 
00122     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00123     Created:    28/6/94
00124     Inputs:     -
00125     Outputs:    -
00126     Returns:    -
00127     Purpose:    Default constructor for a unit.
00128                 Adds the unit to the end of Unit::pUnitList.
00129 
00130 ********************************************************************************************/
00131 
00132 Unit::Unit()
00133 {
00134 }
00135 
00136 /********************************************************************************************
00137 
00138 >   Unit::~Unit()
00139 
00140     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00141     Created:    28/6/94
00142     Inputs:     -
00143     Outputs:    -
00144     Returns:    -
00145     Purpose:    Default destructor for a unit - does nothing
00146 
00147 ********************************************************************************************/
00148 
00149 Unit::~Unit()
00150 {
00151 }
00152 
00153 /********************************************************************************************
00154 
00155 >   static BOOL Unit::Init()
00156 
00157     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00158     Created:    28/6/94
00159     Inputs:     -
00160     Outputs:    -
00161     Returns:    -
00162     Purpose:    Initialises the unit class
00163                 MUST BE CALLED BEFORE ANY OTHER FUNCTION IN THIS CLASS
00164                 Inits the list of units, defines all the default units and places them
00165                 on the list.
00166 
00167 ********************************************************************************************/
00168 
00169 BOOL Unit::Init()
00170 {
00171     return TRUE;
00172 }
00173 
00174 /********************************************************************************************
00175 
00176 >   static BOOL Unit::Deinit()
00177 
00178     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00179     Created:    28/6/94
00180     Inputs:     -
00181     Outputs:    -
00182     Returns:    TRUE if deinitialised OK
00183     Purpose:    Deinitialises the unit class
00184                 It scans Unit::pUnitList, removing and deleting all its members, then
00185                 it destroys the list.
00186 
00187 ********************************************************************************************/
00188 
00189 BOOL Unit::Deinit()
00190 {
00191     return TRUE;
00192 }
00193 
00194 /********************************************************************************************
00195 
00196 >   BOOL Unit::IsDefault()
00197 
00198     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00199     Created:    28/6/94
00200     Inputs:     -
00201     Outputs:    -
00202     Returns:    TRUE if this unit is one of Camelot's default units
00203     Purpose:    Find out if this is a default unit
00204 
00205 ********************************************************************************************/
00206 
00207 BOOL Unit::IsDefault()
00208 {
00209     // Cannot return the state of the flag directly as this is not BOOLEAN due to the
00210     // way bit arrays work. Only reliable test on this is FALSE == 0.
00211     return (Flags.DefaultUnit != 0);
00212 }
00213 
00214 /********************************************************************************************
00215 
00216 >   void Unit::SetDefaultState(BOOL State)
00217 
00218     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00219     Created:    28/6/94
00220     Inputs:     State = new default state
00221     Outputs:    -
00222     Returns:    the old state of the default unit flag
00223     Purpose:    Allows you to set/clear the default unit flag.
00224                 Updated 4/9/95 to return the old state.
00225 
00226 ********************************************************************************************/
00227 
00228 BOOL Unit::SetDefaultState(BOOL State)
00229 {
00230     BOOL OldState = (Flags.DefaultUnit != 0);
00231     Flags.DefaultUnit = State;
00232     
00233     return OldState;    
00234 }
00235 
00236 /********************************************************************************************
00237 
00238 >   BOOL Unit::IsPrefix()
00239 
00240     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00241     Created:    28/6/94
00242     Inputs:     -
00243     Outputs:    -
00244     Returns:    TRUE if this unit's specifier should be placed as a prefix in ed fields
00245                 FALSE means suffix
00246     Purpose:    Find out whether unit specifier should be a prefix or suffix
00247 
00248 ********************************************************************************************/
00249 
00250 BOOL Unit::IsPrefix()
00251 {
00252     // Cannot return the state of the flag directly as this is not BOOLEAN due to the
00253     // way bit arrays work. Only reliable test on this is FALSE == 0.
00254     return (Flags.Prefix != 0);
00255 }
00256 
00257 /********************************************************************************************
00258 
00259 >   BOOL Unit::SetPrefixState(BOOL State)
00260 
00261     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00262     Created:    28/6/94
00263     Inputs:     State = new Prefix state
00264     Outputs:    -
00265     Returns:    The old state of the Prefix flag
00266     Purpose:    Allows you to set/clear the Prefix flag
00267                 Updated 4/9/95 to return the old state.
00268 
00269 ********************************************************************************************/
00270 
00271 BOOL Unit::SetPrefixState(BOOL State)
00272 {
00273     BOOL OldState = (Flags.Prefix != 0);
00274     Flags.Prefix = State;
00275     
00276     return OldState;
00277 }
00278 
00279 /********************************************************************************************
00280 
00281 >   double Unit::GetMillipoints()
00282 
00283     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00284     Created:    28/6/94
00285     Inputs:     -
00286     Outputs:    -
00287     Returns:    The num millipoints in one of these units
00288     Purpose:    Want the number of millipoints in a single instance of this unit?
00289                 This is the call for you!
00290 
00291 ********************************************************************************************/
00292 
00293 double Unit::GetMillipoints()
00294 {
00295     return Millipoints;
00296 }
00297 
00298 /********************************************************************************************
00299 
00300 >   BOOL Unit::SetMillipoints(double NewMillipoints)
00301 
00302     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00303     Created:    28/6/94
00304     Inputs:     NewMillipoints = num millipoints in one of these units
00305     Outputs:    -
00306     Returns:    True is set ok, False otherwise.
00307     Purpose:    Lets you define exactly how big this unit is in the real world, not that we sad
00308                 computer programmers have any idea what the "real world" is, even if it came
00309                 up and generated pulses in a recognisable protocol on our ethernet cable.
00310                 Updated 4/9/95 to return the True if can set the new state ok.
00311 
00312 ********************************************************************************************/
00313 
00314 BOOL Unit::SetMillipoints(double NewMillipoints)
00315 {
00316     // Sanity checks
00317     // - ensure not zero otherwise just wait for those divide by zero errors!
00318     // - check for negative values as well as these will be bad
00319     if (NewMillipoints <= 0)
00320         return FALSE;
00321 
00322     Millipoints = NewMillipoints;
00323 
00324     return TRUE;
00325 }
00326 
00327 /********************************************************************************************
00328 
00329 >   UnitType Unit::GetBaseUnitType()
00330 
00331     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00332     Created:    28/6/94
00333     Inputs:     -
00334     Outputs:    -
00335     Returns:    Unit type this unit is based on
00336     Purpose:    Find out which unit this unit is based on
00337 
00338 ********************************************************************************************/
00339 
00340 UnitType Unit::GetBaseUnitType()
00341 {
00342     return BaseUnitType;
00343 }
00344 
00345 /********************************************************************************************
00346 
00347 >   BOOL Unit::SetBaseUnitType(UnitType NewBaseUnitType)
00348 
00349     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00350     Created:    28/6/94
00351     Inputs:     NewBaseUnitType = the unit this unit is based on
00352     Outputs:    -
00353     Returns:    True is set ok, False otherwise.
00354     Purpose:    Lets you set that base unit type. Oh boy!
00355                 Updated 4/9/95 to return the True if can set the new state ok.
00356 
00357 ********************************************************************************************/
00358 
00359 BOOL Unit::SetBaseUnitType(UnitType NewBaseUnitType)
00360 {
00361     BaseUnitType = NewBaseUnitType;
00362 
00363     return TRUE;
00364 }
00365 
00366 /********************************************************************************************
00367 
00368 >   double Unit::GetBaseNumerator()
00369 
00370     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00371     Created:    28/6/94
00372     Inputs:     -
00373     Outputs:    -
00374     Returns:    Get the base numerator
00375     Purpose:    Get the numerator of the fraction that defines how many BaseUnitTypes are
00376                 in one of these units.
00377                 Millipoints = (BaseNumerator/BaseDenominator)*BaseUnit->GetMillipoints();
00378 
00379 ********************************************************************************************/
00380 
00381 double Unit::GetBaseNumerator()
00382 {
00383     return BaseNumerator;
00384 }
00385 
00386 /********************************************************************************************
00387 
00388 >   void Unit::SetBaseNumerator(double NewBaseNumerator)
00389 
00390     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00391     Created:    28/6/94
00392     Inputs:     NewBaseNumerator = the new numerator value
00393     Outputs:    -
00394     Returns:    True is set ok, False otherwise.
00395     Purpose:    Sets the numerator of the fraction that defines how many BaseUnitTypes are
00396                 in one of these units.
00397                 Millipoints = (BaseNumerator/BaseDenominator)*BaseUnit->GetMillipoints();
00398                 Updated 4/9/95 to return the True if can set the new state ok.
00399 
00400 ********************************************************************************************/
00401 
00402 BOOL Unit::SetBaseNumerator(double NewBaseNumerator)
00403 {
00404     // Sanity checks
00405     // - ensure not zero otherwise just wait for those divide by zero errors!
00406     // - check for negative values as well as these will be bad
00407     if (NewBaseNumerator <= 0)
00408         return FALSE;
00409 
00410     BaseNumerator = NewBaseNumerator;
00411     
00412     return TRUE;
00413 }
00414 
00415 /********************************************************************************************
00416 
00417 >   double Unit::GetBaseDenominator()
00418 
00419     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00420     Created:    28/6/94
00421     Inputs:     -
00422     Outputs:    -
00423     Returns:    Get the base Denominator
00424     Purpose:    Get the Denominator of the fraction that defines how many BaseUnitTypes are
00425                 in one of these units.
00426                 Millipoints = (BaseNumerator/BaseDenominator)*BaseUnit->GetMillipoints();
00427 
00428 ********************************************************************************************/
00429 
00430 double Unit::GetBaseDenominator()
00431 {
00432     return BaseDenominator;
00433 }
00434 
00435 /********************************************************************************************
00436 
00437 >   BOOL Unit::SetBaseDenominator(double NewBaseDenominator)
00438 
00439     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00440     Created:    28/6/94
00441     Inputs:     NewBaseDenominator = the new Denominator value
00442     Outputs:    -
00443     Returns:    True is set ok, False otherwise.
00444     Purpose:    Sets the Denominator of the fraction that defines how many BaseUnitTypes are
00445                 in one of these units.
00446                 Millipoints = (BaseNumerator/BaseDenominator)*BaseUnit->GetMillipoints();
00447                 Updated 4/9/95 to return the True if can set the new state ok.
00448 
00449 ********************************************************************************************/
00450 
00451 BOOL Unit::SetBaseDenominator(double NewBaseDenominator)
00452 {
00453     // Sanity checks
00454     // - ensure not zero otherwise just wait for those divide by zero errors!
00455     // - check for negative values as well as these will be bad
00456     if (NewBaseDenominator <= 0)
00457         return FALSE;
00458 
00459     BaseDenominator = NewBaseDenominator;
00460 
00461     return TRUE;
00462 }
00463 
00464 /********************************************************************************************
00465 
00466 >   String_32 Unit::GetToken()
00467 
00468     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00469     Created:    28/6/94
00470     Inputs:     -
00471     Outputs:    -
00472     Returns:    The token string.
00473     Purpose:    Returns the token string which might be used in say a drop-down list of units.
00474                 This is the full name of the unit in question
00475                 E.g. "centimetres" specifies the default centimetres unit with the
00476                 abbreviation or specifier of "cm".
00477     SeeAlso:    Unit::SetToken; DocUnitList::GetSpecifier;
00478     
00479 ********************************************************************************************/
00480 
00481 String_32 Unit::GetToken()
00482 {
00483     return Token;
00484 }
00485 
00486 /********************************************************************************************
00487 
00488 >   BOOL Unit::SetToken(const String_32& NewToken)
00489 
00490     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00491     Created:    28/6/94
00492     Inputs:     NewToken = new token string
00493     Outputs:    -
00494     Returns:    True is set ok, False otherwise.
00495     Purpose:    Sets the token string for the unit. This is the full name of the unit
00496                 in question
00497                 E.g. "centimetres" specifies the default centimetres unit with the
00498                 abbreviation or specifier of "cm". 
00499                 This must not be blank and must not contain numbers as otherwise number
00500                 parsing may be difficult. Hence, new units should be labelled with A, B .... 
00501                 Hence also, updated to return BOOL 4/9/95 so can return to the setter the
00502                 fact that the new specifier cannot be allowed.
00503     SeeAlso:    Unit::GetToken; DocUnitList::GetSpecifier;
00504 
00505 ********************************************************************************************/
00506 
00507 BOOL Unit::SetToken(const String_32& NewToken)
00508 {
00509     // Sanity checks
00510     // - ensure not zero length
00511     // - should really check for duplicates as unless we allow for overiding of preset units
00512     // - should check for dodgy characters such as numbers as these may be very bad
00513     if (NewToken.Length() == 0)
00514         return FALSE;
00515 
00516     Token = NewToken;
00517 
00518     return TRUE;
00519 }
00520 
00521 /********************************************************************************************
00522 
00523 >   String_32 Unit::GetSpecifier()
00524 
00525     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00526     Created:    28/6/94
00527     Inputs:     -
00528     Outputs:    -
00529     Returns:    The Specifier string
00530     Purpose:    Returns the Specifier string used in in ed fields when specifying units
00531                 E.g. "cm" specifies centimetres
00532     SeeAlso:    DocUnitList::GetSpecifier;
00533 ********************************************************************************************/
00534 
00535 String_32 Unit::GetSpecifier()
00536 {
00537     return Specifier;
00538 }
00539 
00540 /********************************************************************************************
00541 
00542 >   BOOL Unit::SetSpecifier(const String_32& NewSpecifier)
00543 
00544     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00545     Created:    28/6/94
00546     Inputs:     NewSpecifier = new Specifier string
00547     Outputs:    -
00548     Returns:    True is set ok, False otherwise.
00549     Purpose:    Sets the Specifier string for the unit. This is the abbreviation for the unit.
00550                 E.g. "cm" specifies centimetres.
00551                 Might be bad to allow blanks or duplicates of previosly defined specifiers.
00552                 Hence, updated to return BOOL 4/9/95 so can return to the setter the fact that
00553                 the new specifier cannot be allowed.
00554     SeeAlso:    Unit::GetSpecifier; DocUnitList::GetSpecifier;
00555 
00556 ********************************************************************************************/
00557 
00558 BOOL Unit::SetSpecifier(const String_32& NewSpecifier)
00559 {
00560     // Sanity checks
00561     // - ensure not zero length
00562     // - should really check for duplicates as unless we allow for overiding of preset units
00563     // - should check for dodgy characters such as numbers as these are very bad
00564     // - should check for the decimal point character and thousands separator
00565     INT32 LenNewSpecifier = NewSpecifier.Length();  
00566     if (LenNewSpecifier == 0)
00567         return FALSE;
00568 
00569     // Check for the existance of numbers in the string.
00570     // At present, check for the prescence of the fixed decimal point and thousand separator
00571     // characters as no easy way of getting at the values in convert. 
00572     String_32 CheckString( _T("0123456789.,") );
00573     INT32 LenCheckString = CheckString.Length();    
00574     BOOL Found = FALSE;
00575     TCHAR CheckChar;
00576     // Now go through every character in the check string and see if it exists in
00577     // the required new specifier string
00578     for (INT32 i = 0; ( (i < LenNewSpecifier) && (!Found) ); i++)
00579     {
00580         // Get the next character to be checked in the new specifier string
00581         CheckChar = ((const TCHAR*)NewSpecifier)[i];
00582         
00583         // Now compare this against all the characters in the validation string
00584         for (INT32 j = 0; ( (j < LenCheckString) && (!Found) ); j++)
00585         {
00586             if (((TCHAR*)CheckString)[j] == CheckChar)
00587             {
00588                 Found = TRUE;
00589             }
00590         }
00591     }
00592     // We found a problem character so return this result to the caller
00593     if (Found)
00594         return FALSE;       
00595 
00596     Specifier = NewSpecifier;
00597     
00598     return TRUE;
00599 }
00600 
00601 /********************************************************************************************
00602 
00603 >   UnitType Unit::GetUnitType()
00604 
00605     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00606     Created:    28/6/94
00607     Inputs:     -
00608     Outputs:    -
00609     Returns:    The UnitType. This is a enumerated number for all the units defined.
00610     Purpose:    Returns the UnitType of this unit
00611 
00612 ********************************************************************************************/
00613 
00614 UnitType Unit::GetUnitType()
00615 {
00616     return ThisUnitType;
00617 }
00618 
00619 /********************************************************************************************
00620 
00621 >   void Unit::SetUnitType(UnitType NewUnitType)
00622 
00623     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00624     Created:    28/6/94
00625     Inputs:     NewUnitType = new UnitType string
00626     Outputs:    -
00627     Returns:    True is set ok, False otherwise.
00628     Purpose:    Sets the UnitType for the unit. 
00629 
00630 ********************************************************************************************/
00631 
00632 BOOL Unit::SetUnitType(UnitType NewUnitType)
00633 {
00634     ThisUnitType = NewUnitType;
00635     
00636     return TRUE;
00637 }
00638 
00639 //-------------------------------------------------------
00640 //-------------------------------------------------------
00641 //-------------------------------------------------------
00642 //-------------------------------------------------------
00643 
00644 /********************************************************************************************
00645 
00646 >   BOOL DocUnitList::CheckUnitTypesValid()
00647 
00648     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00649     Created:    24/11/95
00650     Inputs:     -
00651     Outputs:    -
00652     Returns:    TRUE if valid, FALSE if not
00653     Purpose:    This checks to see if the UnitType enum and the #defines that specify unit IDs match up.
00654 
00655                 UnitType was originally defined as an enum so that it could by used like a normal type.
00656 
00657                 Later on, internationalisation came along requiring the ability to define the default
00658                 set of units via an .ini file. This required unit types to be specified using #defines so that
00659                 C preprocessing could be used to make the creation of the built-in .ini file easy to read.
00660 
00661                 This conflict meant that it could be possible for these values to get out of step.  This function
00662                 goes some way to ensure that they don't.
00663 
00664 ********************************************************************************************/
00665 
00666 BOOL DocUnitList::CheckUnitTypesValid()
00667 {
00668     BOOL ok = TRUE;
00669 
00670     if (ok) ok = (MILLIMETRES   == UNIT_MILLIMETRES);
00671     if (ok) ok = (CENTIMETRES   == UNIT_CENTIMETRES);
00672     if (ok) ok = (METRES        == UNIT_METRES);
00673     if (ok) ok = (INCHES        == UNIT_INCHES);
00674     if (ok) ok = (FEET          == UNIT_FEET);
00675     if (ok) ok = (YARDS         == UNIT_YARDS);
00676     if (ok) ok = (COMP_POINTS   == UNIT_COMP_POINTS);
00677     if (ok) ok = (PICAS         == UNIT_PICAS);
00678     if (ok) ok = (MILLIPOINTS   == UNIT_MILLIPOINTS);
00679     if (ok) ok = (MILES         == UNIT_MILES);
00680     if (ok) ok = (KILOMETRES    == UNIT_KILOMETRES);
00681     if (ok) ok = (PIXELS        == UNIT_PIXELS);
00682 
00683     ERROR2IF(!ok,FALSE,"One or more enum UnitType values are different to the #define UNIT_ values");
00684 
00685     return (ok);
00686 }
00687 
00688 /********************************************************************************************
00689 
00690 >   DocUnitList::DocUnitList()
00691 
00692     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00693     Created:    5/7/94
00694     Inputs:     -
00695     Outputs:    -
00696     Returns:    -
00697     Purpose:    Default constructor for a document unit list.
00698                 Initialises the object.
00699 
00700 ********************************************************************************************/
00701 
00702 DocUnitList::DocUnitList()
00703 {
00704     NumUnits = 0;
00705     NextUnitNum = 0;
00706     NextUnitType = NUM_DEFAULT_UNIT_TYPES;
00707     DefaultsMade = FALSE;
00708     LastEditedUnit = NOTYPE;
00709 
00710     SetScaleUnits(AUTOMATIC);
00711     SetPageUnits(CENTIMETRES);
00712     SetFontUnits(COMP_POINTS);
00713 }
00714 
00715 /********************************************************************************************
00716 
00717 >   DocUnitList::~DocUnitList()
00718 
00719     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00720     Created:    5/7/94
00721     Inputs:     -
00722     Outputs:    -
00723     Returns:    -
00724     Purpose:    Default destructor for a document unit list.
00725                 Deletes all units in the list
00726 
00727 ********************************************************************************************/
00728 
00729 DocUnitList::~DocUnitList()
00730 {
00731 /*  Unit* pUnit = (Unit*)this->GetHead();
00732     Unit* pOldUnit;
00733 
00734     while (pUnit != NULL)
00735     {
00736         pOldUnit = pUnit;
00737         pUnit = (Unit*)this->GetNext(pOldUnit);
00738         this->RemoveItem(pOldUnit);
00739         delete pOldUnit;
00740     }
00741 */
00742     ListItem* pItem;
00743 
00744     while ((pItem = this->RemoveHead()) != NULL)
00745         delete pItem;
00746 }
00747 
00748 /********************************************************************************************
00749 
00750 >   static BOOL DocUnitList::Init()
00751 
00752     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00753     Created:    5/7/94
00754     Inputs:     -
00755     Outputs:    -
00756     Returns:    -
00757     Purpose:    Initialises the DocUnitList class
00758                 MUST BE CALLED BEFORE ANY OTHER FUNCTION IN THIS CLASS
00759                 
00760 ********************************************************************************************/
00761 
00762 BOOL DocUnitList::Init()
00763 {
00764     return CheckUnitTypesValid();
00765 }
00766 
00767 /********************************************************************************************
00768 
00769 >   static BOOL DocUnitList::Deinit()
00770 
00771     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00772     Created:    5/7/94
00773     Inputs:     -
00774     Outputs:    -
00775     Returns:    TRUE if deinitialised OK
00776     Purpose:    Deinitialises the doc unit list class
00777 
00778 ********************************************************************************************/
00779 
00780 BOOL DocUnitList::Deinit()
00781 {
00782     return TRUE;
00783 }
00784 
00785 /********************************************************************************************
00786 
00787 >   BOOL DocUnitList::MakeNewUnit(Unit** ppUnit,BOOL Initialise = TRUE)
00788 
00789     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00790     Created:    5/7/94
00791     Inputs:     ppUnit = ptr to ptr to a unit
00792                 Initialise -    if TRUE then the new unit is initialised with 
00793                                 senisble values.
00794                                 Also, UnitMsg::NEW is only broadcast when this is TRUE
00795     Outputs:    If OK, *ppUnit = ptr to the new unit
00796     Returns:    TRUE if OK, i.e. successfully created and initialised a new unit
00797     Purpose:    Defines all the default units and places them on the list.
00798     Errors:     Can only be called once per instance. Errors if called again.
00799 
00800 ********************************************************************************************/
00801 
00802 BOOL DocUnitList::MakeNewUnit(Unit** ppUnit,BOOL Initialise)
00803 {
00804     Unit* pUnit = new Unit;
00805     if (pUnit == NULL) return FALSE;
00806 
00807     if (Initialise)
00808     {
00809         String_32 num(_R(IDS_UNITS_NEW_UNIT_ABBREV));
00810         String_32 abbrev(_R(IDS_UNITS_NEW_UNIT_ABBREV));
00811         
00812         INT32 i;
00813         for( i = 0;i<(NextUnitNum / 20) && i<10;i++)
00814             num += abbrev;
00815 
00816         ((LPTSTR) num)[i] += ((NextUnitNum++) % 20);
00817         
00818         String_32 TokenStr(_R(IDS_UNITS_NEW_UNIT_NAME));
00819         String_32 SpecifierStr(_R(IDS_UNITS_NEW_UNIT_SPECIFIER));
00820         TokenStr += num;
00821         SpecifierStr += num;
00822 
00823         pUnit->SetUnitType((UnitType) NextUnitType++);
00824         pUnit->SetDefaultState(FALSE);
00825         pUnit->SetPrefixState(FALSE);
00826         pUnit->SetBaseUnitType(MILLIMETRES);
00827         pUnit->SetBaseNumerator(10);
00828         pUnit->SetBaseDenominator(1);
00829         pUnit->SetMillipoints(CM_MP_VAL);
00830         pUnit->SetToken(TokenStr);
00831         pUnit->SetSpecifier(SpecifierStr);
00832     }
00833 
00834     this->AddTail(pUnit);
00835     *ppUnit = pUnit;
00836     NumUnits++;
00837 
00838     if (Initialise)
00839     {
00840         // Tell everybody that the unit has been created
00841         BROADCAST_TO_ALL(UnitMsg(this,pUnit->GetUnitType(),UnitMsg::NEW));
00842     }
00843 
00844     return TRUE;
00845 }
00846 
00847 /********************************************************************************************
00848 
00849 >   UnitReason DocUnitList::DeleteUnit(UnitType ThisUnitType)
00850 
00851     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00852     Created:    8/7/94
00853     Inputs:     ThisUnitType = the type of the unit to delete
00854     Outputs:    -
00855     Returns:    UNITREASON_OK             -  The unit has been deleted
00856                 UNITREASON_HASDESCENDENTS -  Other units are based on this unit
00857                                              e.g. cm is based on mm
00858                 UNITREASON_BEINGUSED      -  This unit type is being used in the document
00859                                              e.g. page units may use this unit
00860     Purpose:    Lets you delete a unit from the list
00861     Errors:     Can only be called once per instance. Errors if called again.
00862 
00863 ********************************************************************************************/
00864 
00865 UnitReason DocUnitList::DeleteUnit(UnitType ThisUnitType)
00866 {
00867     if (HasDescendents(ThisUnitType))
00868         return UNITREASON_HASDESCENDENTS;
00869 
00870     if (PageUnits  == ThisUnitType ||
00871         ScaleUnits == ThisUnitType ||
00872         FontUnits  == ThisUnitType)
00873         return UNITREASON_BEINGUSED;
00874 
00875     // Tell everybody that the unit is about to be deleted)
00876     BROADCAST_TO_ALL(UnitMsg(this,ThisUnitType,UnitMsg::BEFOREDELETE));
00877 
00878     this->RemoveItem(FindUnit(ThisUnitType));
00879     NumUnits--;
00880 
00881     // Tell everybody that the unit is about to be deleted)
00882     BROADCAST_TO_ALL(UnitMsg(this,NOTYPE,UnitMsg::AFTERDELETE));
00883 
00884     return UNITREASON_OK;
00885 }
00886 
00887 /********************************************************************************************
00888 
00889 >   INT32 DocUnitList::GetNumUnits()
00890 
00891     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00892     Created:    5/7/94
00893     Inputs:     -
00894     Outputs:    -
00895     Returns:    The num defined units in the list
00896     Purpose:    Returns the num units in the list
00897 
00898 ********************************************************************************************/
00899 
00900 INT32 DocUnitList::GetNumUnits()
00901 {
00902     return NumUnits;
00903 }
00904 
00905 /********************************************************************************************
00906 
00907 >   Unit* DocUnitList::FindUnit(UnitType ThisUnit)
00908 
00909     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00910     Created:    5/7/94
00911     Inputs:     ThisUnit = the unit type of the unit we want
00912     Outputs:    -
00913     Returns:    Ptr to the unit.
00914                 NULL is returned if not found.
00915     Purpose:    Find a unit using its type
00916 
00917 ********************************************************************************************/
00918 
00919 Unit* DocUnitList::FindUnit(UnitType ThisUnit)
00920 {
00921     Unit* pUnit = (Unit*) this->GetHead();
00922 
00923     while (pUnit != NULL)
00924     {
00925         if (pUnit->GetUnitType() == ThisUnit)
00926             return pUnit;
00927 
00928         pUnit = (Unit*) this->GetNext(pUnit);
00929     }
00930 
00931     ERROR3IF(pUnit == NULL,"Can't find the unit");
00932 
00933     return NULL;
00934 }
00935 
00936 /********************************************************************************************
00937 
00938 >   Unit* DocUnitList::FindUnit(INT32 Index)
00939 
00940     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00941     Created:    5/5/94
00942     Inputs:     Index = indexes directly into the unit list (0 = first unit in list)
00943     Outputs:    -
00944     Returns:    Ptr to the unit.
00945                 NULL is returned if not found.
00946     Purpose:    Find a unit by index
00947 
00948 ********************************************************************************************/
00949 
00950 Unit* DocUnitList::FindUnit(INT32 Index)
00951 {
00952     ERROR3IF(Index < 0,"DocUnitList::FindUnit A negative index? Now there's a novelty");
00953     ERROR3IF(Index >= NumUnits,"DocUnitList::FindUnit Index is greater than num units in system");
00954     if (Index < 0 || Index >= NumUnits)
00955         return NULL;    // Problem, so return quickly
00956 
00957     Unit* pUnit = (Unit*) this->GetHead();
00958 
00959     while ((pUnit != NULL) && (Index > 0))
00960     {
00961         pUnit = (Unit*) this->GetNext(pUnit);
00962         Index--;
00963     }
00964 
00965     ERROR3IF(pUnit == NULL,"DocUnitList::FindUnit Can't find the unit");
00966 
00967     return pUnit;
00968 }
00969 
00970 /*********************************************************************************************
00971 
00972 > UnitType DocUnitList::FindUnitType(const StringBase& Str)
00973 
00974 Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00975 Created:    5/7/94
00976 Inputs:     Str = string specifying a unit specifier
00977 Returns:    The type of unit represented by the string passed in
00978 Purpose:    Identifies the unit by the unit specifier string
00979             E.g. 'cm', 'km','mi', 'bananas', etc
00980             If the unit is not recognised, NOTYPE is returned
00981 SeeAlso:    DocUnitList::FindUnitTypeFromToken;
00982 
00983 *********************************************************************************************/
00984 
00985 UnitType DocUnitList::FindUnitType(const StringBase& Str)
00986 {
00987     String_32 Specifier;
00988     String_32 SearchStr;
00989     INT32 len = min(32,Str.Length());
00990     const TCHAR* p1 = (const TCHAR *) Str;
00991     TCHAR* p2 = (TCHAR *) SearchStr;
00992 
00993     // Copy param Str into SearchStr
00994     INT32 i;
00995     for (i=0;i<len;i++)
00996         p2[i] = p1[i];
00997 
00998     p2[i] = 0;              // Terminate
00999     SearchStr.toLower();    // and convert to lower case
01000 
01001     Unit* pUnit = (Unit*) this->GetHead();
01002 
01003     while (pUnit != NULL)
01004     {
01005         Specifier = pUnit->GetSpecifier();
01006         Specifier.toLower();
01007 
01008         if (Specifier == SearchStr)
01009             return (pUnit->GetUnitType());
01010 
01011         pUnit = (Unit*) this->GetNext(pUnit);
01012     }
01013 
01014     return NOTYPE;
01015 }
01016 
01017 
01018 /*********************************************************************************************
01019 
01020 > UnitType DocUnitList::FindUnitTypeFromToken(const StringBase& Str)
01021 
01022 Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01023 Created:    1/9/95
01024 Inputs:     Str = string specifying a unit token
01025 Returns:    The type of unit represented by the string passed in
01026 Purpose:    Identifies the unit by the unit token string
01027             E.g. 'cm', 'km','mi', 'bananas', etc
01028             If the unit is not recognised, NOTYPE is returned
01029 SeeAlso:    DocUnitList::FindUnitType;
01030 
01031 *********************************************************************************************/
01032 
01033 UnitType DocUnitList::FindUnitTypeFromToken(const StringBase& Str)
01034 {
01035     String_32 Token;
01036     String_32 SearchStr;
01037     INT32 len = min(32,Str.Length());
01038     const TCHAR* p1 = Str;
01039     TCHAR* p2 = SearchStr;
01040 
01041     // Copy param Str into SearchStr
01042     INT32 i;
01043     for (i=0;i<len;i++)
01044         p2[i] = p1[i];
01045 
01046     p2[i] = 0;              // Terminate
01047     SearchStr.toLower();    // and convert to lower case
01048 
01049     Unit* pUnit = (Unit*) this->GetHead();
01050 
01051     while (pUnit != NULL)
01052     {
01053         Token = pUnit->GetToken();
01054         Token.toLower();
01055 
01056         if (Token == SearchStr)
01057             return (pUnit->GetUnitType());
01058 
01059         pUnit = (Unit*) this->GetNext(pUnit);
01060     }
01061 
01062     return NOTYPE;
01063 }
01064 
01065 
01066 /*********************************************************************************************
01067 
01068 > INT32 DocUnitList::FindUnitIndex(UnitType ThisUnit)
01069 
01070 Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01071 Created:    5/7/94
01072 Inputs:     ThisUnit = Type of unit you want
01073 Returns:    The position of this unit in the list of units.
01074 Purpose:    Get the position of the unit in the list of units.
01075             Used mainly in conjunction with drop-down lists of units
01076 
01077 *********************************************************************************************/
01078 
01079 INT32   DocUnitList::FindUnitIndex(UnitType ThisUnit)
01080 {
01081     Unit* pUnit = (Unit*) this->GetHead();
01082     INT32 Index = 0;
01083 
01084     while ((pUnit != NULL) && (pUnit->GetUnitType() != ThisUnit))
01085     {
01086         pUnit = (Unit*) this->GetNext(pUnit);
01087         Index++;
01088     }
01089 
01090     ERROR3IF(pUnit == NULL,"Can't find the unit");
01091     if (pUnit == NULL) Index = 0;   // Safe for retail builds
01092 
01093     return Index;
01094 }
01095 
01096 
01097 /*********************************************************************************************
01098 
01099 > Unit* DocUnitList::FindFirstUserUnit()
01100 
01101 Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01102 Created:    5/7/94
01103 Inputs:     -
01104 Outputs:    -
01105 Returns:    Ptr to the first user (or non-default) unit in the list
01106             NULL is returned if all the units are default ones, or the list is empty
01107 Purpose:    Lets you get hold of that elusive first user-defined unit.
01108             All units are either default or user-defined units.
01109 
01110 *********************************************************************************************/
01111 
01112 Unit* DocUnitList::FindFirstUserUnit()
01113 {
01114     // Get a pointer to the first unit in the list
01115     Unit* pUnit = (Unit*) this->GetHead();
01116 
01117     while (pUnit != NULL)
01118     {
01119         if (!pUnit->IsDefault())
01120             return pUnit;
01121 
01122         pUnit = (Unit*) this->GetNext(pUnit);
01123     }
01124 
01125     return (pUnit);
01126 }
01127 
01128 
01129 /*********************************************************************************************
01130 
01131 > Unit* DocUnitList::FindNextUserUnit(Unit* pUnit)
01132 
01133 Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01134 Created:    5/7/94
01135 Inputs:     pUnit = ptr to a unit in the list
01136 Outputs:    -
01137 Returns:    Ptr to the first user (or non-default) unit in the list
01138             NULL is returned if all the units are default ones, or the list is empty
01139 Purpose:    Lets you get hold of that elusive first user-defined unit.
01140             All units are either default or user-defined units.
01141 
01142 *********************************************************************************************/
01143 
01144 Unit* DocUnitList::FindNextUserUnit(Unit* pUnit)
01145 {
01146     pUnit = (Unit*) this->GetNext(pUnit);
01147 
01148     while (pUnit != NULL)
01149     {
01150         if (!pUnit->IsDefault())
01151             return pUnit;
01152 
01153         pUnit = (Unit*) this->GetNext(pUnit);
01154     }
01155 
01156     return (pUnit);
01157 }
01158 
01159 
01160 /*********************************************************************************************
01161 
01162 > Unit* DocUnitList::FindUserUnit(INT32 Index)
01163 
01164 Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01165 Created:    7/7/94
01166 Inputs:     Index = the index into the list of user-defined units
01167 Outputs:    -
01168 Returns:    Ptr to the Index-th user (or non-default) unit in the list
01169             NULL is returned if there isn't an Index-th user unit
01170 Purpose:    Lets you get hold of that elusive Index-th user-defined unit.
01171 SeeAlso:    FindFirstUserUnit,FindNextUserUnit
01172 
01173 *********************************************************************************************/
01174 
01175 Unit* DocUnitList::FindUserUnit(INT32 Index)
01176 {
01177     if (Index < 0) return NULL;
01178 
01179     Unit* pUnit = FindFirstUserUnit();
01180 
01181     while (pUnit != NULL && Index > 0)
01182     {
01183         pUnit = FindNextUserUnit(pUnit);
01184         Index--;
01185     }
01186 
01187     return (pUnit);
01188 }
01189 
01190 
01191 /********************************************************************************************
01192 
01193 > void DocUnitList::RecalcUnit(Unit* pThisUnit)
01194 
01195     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01196     Created:    5/7/94
01197     Inputs:     pThisUnit = unit to recalculate
01198     Outputs:    -
01199     Returns:    -
01200     Purpose:    Recalculates the number of millipoints in this unit by multiplying the ratio
01201                 between this and the base unit, with the num millipoints in the base unit.
01202                 E.g. Recalc Metres :
01203                     Num Millipoints in metre = Num MP in centimetre * 100;
01204                 IMPORTANT: This can only recalculate units that are based on another unit.
01205                 If the unit is not based on another unit (i.e. its base type is NOTYPE) then
01206                 nothing happens.
01207 
01208 ********************************************************************************************/
01209 
01210 void DocUnitList::RecalcUnit(Unit* pThisUnit)
01211 {
01212     if (pThisUnit->GetBaseUnitType() == NOTYPE) return;
01213 
01214     Unit* pBaseUnit = FindUnit(pThisUnit->GetBaseUnitType());
01215     double ratio = pThisUnit->GetBaseNumerator() / pThisUnit->GetBaseDenominator();
01216 
01217     pThisUnit->SetMillipoints(pBaseUnit->GetMillipoints() * ratio);
01218 }
01219 
01220 /********************************************************************************************
01221 
01222 > BOOL DocUnitList::RecalcUnit(Unit* pThisUnit,UnitType ChangedUnitType)
01223 
01224     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01225     Created:    5/7/94
01226     Inputs:     pThisUnit       = Unit to ask to recalculate
01227                 ChangedUnitType = the unit type that has changed it's definition
01228                                   i.e. the unit's Millipoint value has changed
01229     Outputs:    -
01230     Returns:    TRUE  - This unit has changed also as a result of unit ChangedUnitType changing
01231                 FALSE - Hasn't changed
01232     Purpose:    This recalcs the unit's definition (i.e. the num millipoints that make it up)
01233                 if it is a descendent of ChangedUnitType.
01234 
01235 ********************************************************************************************/
01236 /*  Implementation
01237 
01238     Principle:
01239 
01240         A->B->C (B is based on A, and C is based on B)
01241         If A changes, then B and C must be recalculated
01242         It's important that B is recalculated before C
01243 
01244     Algorithm:
01245 
01246         Is this unit based on another?
01247             If no, return FALSE;
01248 
01249         Is this unit based on the changed unit?
01250             Is yes, recalc and return TRUE;
01251 
01252         Find this unit's base unit
01253 
01254         Has this unit's base unit recalculated as a result of the
01255         original unit change?
01256             If yes, recalc and return TRUE;
01257 */
01258 
01259 BOOL DocUnitList::RecalcUnit(Unit* pThisUnit,UnitType ChangedUnitType)
01260 {
01261     if (pThisUnit->GetBaseUnitType() == NOTYPE)
01262         return FALSE;
01263 
01264     if (pThisUnit->GetBaseUnitType() == ChangedUnitType)
01265     {
01266         RecalcUnit(pThisUnit);
01267         return TRUE;
01268     }
01269 
01270     Unit* pBaseUnit = FindUnit(pThisUnit->GetBaseUnitType());
01271 
01272     if (RecalcUnit(pBaseUnit,ChangedUnitType))
01273     {
01274         RecalcUnit(pThisUnit);
01275         return TRUE;
01276     }
01277 
01278     return FALSE;
01279 }
01280 
01281 /********************************************************************************************
01282 
01283 > void DocUnitList::UnitHasChanged(UnitType ChangedUnitType)
01284 
01285     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01286     Created:    5/7/94
01287     Inputs:     ChangedUnitType = the unit type that has changed it's definition
01288                                   i.e. the unit's Millipoint value has changed
01289     Outputs:    -
01290     Returns:    -
01291     Purpose:    This informs the class that the definition of a unit has changed.
01292                 It ensures that all units that are descendents of the changed unit
01293                 are recalculated.
01294 
01295 ********************************************************************************************/
01296 
01297 void DocUnitList::UnitHasChanged(UnitType ChangedUnitType)
01298 {
01299     Unit* pUnit = (Unit*) this->GetHead();
01300 
01301     while (pUnit != NULL)
01302     {
01303         RecalcUnit(pUnit,ChangedUnitType);
01304         pUnit = (Unit*) this->GetNext(pUnit);
01305     }
01306 
01307     // Tell everybody that the unit has changed
01308     BROADCAST_TO_ALL(UnitMsg(this,ChangedUnitType,UnitMsg::CHANGED));
01309 }
01310 
01311 /********************************************************************************************
01312 
01313 > BOOL DocUnitList::IsDescendent(Unit* pThisUnit, UnitType NewUnitType)
01314 
01315     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01316     Created:    5/7/94
01317     Inputs:     pThisUnit = ptr to unit in question
01318                 NewUnitType = the unit type to check against accendency
01319     Outputs:    -
01320     Returns:    TRUE  - This unit is a descendent of NewUnitType
01321                 FALSE - Never heard of the unit guv.
01322     Purpose:    Checks to see if this unit is a descendent of NewUnitType
01323                 E.g. A->B->C (B is based on A, and C is based on B)
01324                 Both B and C are descendents of A
01325 
01326 ********************************************************************************************/
01327 /*  Implementation note.
01328 
01329     Algorithm:
01330 
01331         Is unit based on another?
01332             If no, return FALSE;
01333 
01334         Is unit based on the new unit?
01335             If yes, return TRUE
01336 
01337         Check to see if unit's base unit is a descendent of the new base unit
01338 */
01339 
01340 BOOL DocUnitList::IsDescendent(Unit* pThisUnit,UnitType NewUnitType)
01341 {
01342     if (pThisUnit->GetBaseUnitType() == NOTYPE)
01343         return FALSE;   
01344 
01345     if (pThisUnit->GetBaseUnitType() == NewUnitType)
01346         return TRUE;
01347 
01348     Unit* pBaseUnit = FindUnit(pThisUnit->GetBaseUnitType());
01349 
01350     return (IsDescendent(pBaseUnit,NewUnitType));
01351 }
01352 
01353 /********************************************************************************************
01354 
01355 > BOOL DocUnitList::HasDescendents(UnitType ThisUnitType)
01356 
01357     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01358     Created:    8/7/94
01359     Inputs:     ThisUnitType = The unit type to check for decendents
01360     Outputs:    -
01361     Returns:    TRUE  - This unit is has one or more descendents
01362                 FALSE - No other unit is based on this unit
01363     Purpose:    Finds out is there are other units that are decendents of this unit,
01364                 i.e. other units that are based on this unit either directly or indirectly
01365                 e.g. A->B->C (B is based on A, C is based on B). 
01366                 Both A nd B have decendents. C does not.
01367 
01368 ********************************************************************************************/
01369 
01370 BOOL DocUnitList::HasDescendents(UnitType ThisUnitType)
01371 {
01372     Unit* pUnit = (Unit*) this->GetHead();
01373 
01374     while (pUnit != NULL)
01375     {
01376         if (pUnit->GetUnitType() != ThisUnitType)
01377         {
01378             if (IsDescendent(pUnit,ThisUnitType))
01379                 return TRUE;
01380         }
01381         pUnit = (Unit*) this->GetNext(pUnit);
01382     }
01383 
01384     return FALSE;
01385 }
01386 
01387 /********************************************************************************************
01388 
01389 >   BOOL DocUnitList::SetBaseUnitType(Unit* pThisUnit,UnitType NewBaseUnitType)
01390 
01391     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01392     Created:    5/7//94
01393     Inputs:     NewBaseUnitType = the unit this unit is based on
01394     Outputs:    -
01395     Returns:    TRUE if all went OK
01396                 FALSE if NewBaseUnitType is this unit or a descendent of this unit
01397     Purpose:    Lets you set that base unit type, dude!
01398 
01399 ********************************************************************************************/
01400 
01401 BOOL DocUnitList::SetBaseUnitType(Unit* pThisUnit,UnitType NewBaseUnitType)
01402 {
01403     if (pThisUnit->GetUnitType() == NewBaseUnitType)
01404         return FALSE;
01405 
01406     if (NewBaseUnitType != NOTYPE)
01407     {
01408         Unit* pNewBaseUnit = FindUnit(NewBaseUnitType);
01409         
01410         if (IsDescendent(pNewBaseUnit,pThisUnit->GetUnitType()))
01411             return FALSE;
01412     }
01413 
01414     pThisUnit->SetBaseUnitType(NewBaseUnitType);
01415     return TRUE;
01416 }
01417 
01418 /********************************************************************************************
01419 
01420 >   static DocUnitList* DocUnitList::GetCurrentDocUnitList()
01421 
01422     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01423     Created:    5/7/94
01424     Inputs:     -
01425     Outputs:    -
01426     Returns:    Ptr to the doc unit list object of the current doc, or NULL if there isn't one
01427     Purpose:    Lets you set that base unit type, dude!
01428 
01429 ********************************************************************************************/
01430 
01431 DocUnitList* DocUnitList::GetCurrentDocUnitList()
01432 {
01433     // Get the current doc and return if there is not one
01434     Document* pDoc = Document::GetCurrent();
01435     //ERROR3IF(pDoc==NULL, "Can't find the current doc");
01436     if (pDoc==NULL)
01437         return NULL;
01438 
01439     // get the Unit list and return it
01440 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
01441     ERROR3IF(pDoc->GetDocUnitList()==NULL, "Can't find the doc unit list in the current doc");
01442 #endif
01443     return (pDoc->GetDocUnitList());
01444 }
01445 
01446 /********************************************************************************************
01447 
01448 >   void DocUnitList::SetScaleUnits(UnitType NewUnits)
01449 
01450     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01451     Created:    5/7/94
01452     Inputs:     NewUnits = the new units to use
01453     Outputs:    -
01454     Returns:    -
01455     Purpose:    Sets the scale units of the object directly
01456     SeeAlso:    -
01457 
01458 ********************************************************************************************/
01459 
01460 void DocUnitList::SetScaleUnits(UnitType NewUnits)
01461 {
01462     ScaleUnits = NewUnits;
01463 }
01464 
01465 /********************************************************************************************
01466 
01467 >   UnitType DocUnitList::GetScaleUnits()
01468 
01469     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01470     Created:    5/7/94
01471     Inputs:     -
01472     Outputs:    -
01473     Returns:    The scale units of this object
01474     Purpose:    For getting hold of those pesky scale units
01475     SeeAlso:    -
01476 
01477 ********************************************************************************************/
01478 
01479 UnitType DocUnitList::GetScaleUnits()
01480 {
01481     return ScaleUnits;
01482 }
01483 
01484 /********************************************************************************************
01485 
01486 >   void DocUnitList::SetPageUnits(UnitType NewUnits)
01487 
01488     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01489     Created:    5/7/94
01490     Inputs:     NewUnits = the new units to use
01491     Outputs:    -
01492     Returns:    -
01493     Purpose:    Sets the page units of the object directly
01494     SeeAlso:    -
01495 
01496 ********************************************************************************************/
01497 
01498 void DocUnitList::SetPageUnits(UnitType NewUnits)
01499 {
01500     PageUnits = NewUnits;
01501 }
01502 
01503 /********************************************************************************************
01504 
01505 >   UnitType DocUnitList::GetPageUnits()
01506 
01507     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01508     Created:    5/7/94
01509     Inputs:     -
01510     Outputs:    -
01511     Returns:    The page units of this object
01512     Purpose:    For getting hold of those pesky page units
01513     SeeAlso:    -
01514 
01515 ********************************************************************************************/
01516 
01517 UnitType DocUnitList::GetPageUnits()
01518 {
01519     return (PageUnits);
01520 }
01521 
01522 /********************************************************************************************
01523 
01524 >   void DocUnitList::SetFontUnits(UnitType NewUnits)
01525 
01526     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01527     Created:    5/7/94
01528     Inputs:     NewUnits = the new units to use
01529     Outputs:    -
01530     Returns:    -
01531     Purpose:    Sets the font units of the object directly
01532     SeeAlso:    -
01533 
01534 ********************************************************************************************/
01535 
01536 void DocUnitList::SetFontUnits(UnitType NewUnits)
01537 {
01538     FontUnits = NewUnits;
01539 }
01540 
01541 /********************************************************************************************
01542 
01543 >   UnitType DocUnitList::GetFontUnits()
01544 
01545     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01546     Created:    5/7/94
01547     Inputs:     -
01548     Outputs:    -
01549     Returns:    The font units of this object
01550     Purpose:    For getting hold of those pesky font units
01551     SeeAlso:    -
01552 
01553 ********************************************************************************************/
01554 
01555 UnitType DocUnitList::GetFontUnits()
01556 {
01557     return (FontUnits);
01558 }
01559 
01560 /********************************************************************************************
01561 
01562 >   String_32 DocUnitList::GetToken(UnitType ThisUnitType)
01563 
01564     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01565     Created:    5/7/94
01566     Inputs:     ThisUnitType = type of unit you want token of
01567     Outputs:    -
01568     Returns:    The token for the unit, i.e. the string that describes the unit
01569                 e.g. "Centimetres"
01570     Purpose:    Easy way of getting a unit token string.
01571                 IMPORTANT: This is a general function that can cope with special UnitType values
01572                 like AUTOMATIC and NOTYPE, i.e. types that don't correspond to an actual instance
01573                 of Unit.
01574     SeeAlso:    DocUnitList::GetSpecifier; Unit::GetSpecifier;
01575 
01576 ********************************************************************************************/
01577 
01578 String_32 DocUnitList::GetToken(UnitType ThisUnitType)
01579 {        
01580     String_32 Str;
01581     
01582     switch (ThisUnitType)
01583     {
01584         case AUTOMATIC :
01585             Str = String_32(_R(IDS_AUTOMATIC));
01586             break;
01587 
01588         case NOTYPE :
01589             Str = String_32(_R(IDS_NOTYPE));
01590             break;
01591 
01592         default :
01593             {
01594                 Unit * pUnit = NULL;
01595                 pUnit = FindUnit(ThisUnitType);
01596                 if (pUnit)
01597                     Str = pUnit->GetToken();
01598                 else
01599                     Str = String_32(_R(IDS_NOTYPE));    
01600             }
01601             
01602             break;
01603     }
01604 
01605     return Str;
01606 }
01607 
01608 /********************************************************************************************
01609 
01610 >   String_32 DocUnitList::GetSpecifier(UnitType ThisUnitType)
01611 
01612     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01613     Created:    1/9/95
01614     Inputs:     ThisUnitType = type of unit you want specfier of
01615     Outputs:    -
01616     Returns:    The Specifier for the unit, i.e. the string that describes the unit
01617                 e.g. "cm"
01618     Purpose:    Easy way of getting a unit specifier string.
01619                 If bad UnitType and hence no unit found, returns a blank string 
01620     SeeAlso:    DocUnitList::GetToken; Unit::GetToken
01621 
01622 ********************************************************************************************/
01623 
01624 String_32 DocUnitList::GetSpecifier(UnitType ThisUnitType)
01625 {        
01626     String_32 Str = _T("");
01627     
01628     Unit* pUnit = NULL;
01629     pUnit = FindUnit(ThisUnitType);
01630     if (pUnit)
01631         Str = pUnit->GetSpecifier();
01632 
01633     return Str;
01634 }
01635 
01636 //----------------------------------------------------------------------------------
01637 //----------------------------------------------------------------------------------
01638 //----------------------------------------------------------------------------------
01639 
01640 // Tokens used in winoil\units.ini
01641 static struct
01642 {
01643     TCHAR*  Token;
01644 } TokenTable[] = 
01645 {
01646     {_T("Unit")},
01647     {_T("PageUnits")},
01648     {_T("FontUnits")},
01649     {_T("UnitsEnd")}
01650 };
01651 
01652 // Token indexes for the above tokens
01653 enum UnTokenIndex
01654 {
01655     UnTOKEN_NONE = -1,
01656     TOKEN_UNIT,
01657     TOKEN_PAGEUNITS,
01658     TOKEN_FONTUNITS,
01659     TOKEN_UNITSEND,
01660     // Add new token indexs BEFORE NUM_TOKENS
01661     UnNUM_TOKENS
01662 };
01663 
01664 // function for turning a token into a token indexes
01665 static UnTokenIndex FindToken(const TCHAR* Token)
01666 {
01667     for (INT32 i = 0; i < UnNUM_TOKENS; i++)
01668         if (camStrcmp(TokenTable[i].Token,Token) == 0) return (UnTokenIndex) i;
01669 
01670     return UnTOKEN_NONE;
01671 }
01672 
01673 
01674 /********************************************************************************************
01675 
01676 > BOOL DocUnitList::MakeDefaultUnits()
01677 
01678     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01679     Created:    23/11/95
01680     Inputs:     -
01681     Outputs:    -
01682     Returns:    TRUE if OK, FALSE otherwise
01683     Purpose:    This creates the default units for a document.
01684                 It tries to find the default units via three sources (highest priority first):
01685                     Disk (Not implemented yet)
01686                     Bound-in resource (defined in winoil\units.ini)
01687                     Hard-wired defaults.
01688     SeeAlso:    -
01689 
01690 ********************************************************************************************/
01691 
01692 BOOL DocUnitList::MakeDefaultUnits()
01693 {
01694     ERROR3IF(DefaultsMade,"MakeDefaultUnits has already been called for this instance of DocUnitList");
01695     if (DefaultsMade) return TRUE;
01696     
01697     // Ensure the list is empty before proceeding
01698     DeleteAll();
01699 
01700     BOOL ok = TRUE;
01701     ok = ReadUnitsFromDisk();
01702 
01703 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
01704     if (!ok) ok = ReadUnitsFromRes();
01705 #endif
01706 
01707     if (!ok) ok = MakeFactoryDefaultUnits();
01708 
01709     DefaultsMade = ok;
01710 
01711     return (ok);
01712 }
01713 
01714 /********************************************************************************************
01715 
01716 > BOOL DocUnitList::ReadUnitsFromDisk()
01717 
01718     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01719     Created:    23/11/95
01720     Inputs:     -
01721     Outputs:    -
01722     Returns:    TRUE if OK, FALSE otherwise
01723     Purpose:    Reads the unit definitions from disk (i.e. writable media)
01724     SeeAlso:    -
01725 
01726 ********************************************************************************************/
01727 
01728 BOOL DocUnitList::ReadUnitsFromDisk()
01729 {   
01730     // Not yet implemented
01731 
01732     return FALSE;
01733 }
01734 
01735 /********************************************************************************************
01736 
01737 > BOOL DocUnitList::ReadUnitsFromRes()
01738 
01739     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01740     Created:    23/11/95
01741     Inputs:     -
01742     Outputs:    -
01743     Returns:    TRUE if OK, FALSE otherwise
01744     Purpose:    Reads the unit definitions from the bound in resource.
01745     SeeAlso:    -
01746 
01747 ********************************************************************************************/
01748 
01749 BOOL DocUnitList::ReadUnitsFromRes()
01750 {
01751     PORTNOTETRACE("other","Removed DocUnitList::ReadUnitsFromRes()");
01752 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
01753     // Remove all previously defined units.  We're starting from scratch
01754     DeleteAll();
01755 
01756     CCResTextFile file;             // Resource File
01757 
01758     BOOL ok = file.open(_R(IDM_DEFAULT_UNITS),_R(IDT_CAM_UNITS));       // Open resource
01759 
01760     if (ok)
01761     {
01762         ok = ReadUnitsFromFile(file);
01763         file.close();
01764     }
01765 
01766     return (ok);
01767 #else
01768     return FALSE;
01769 #endif
01770 }
01771 
01772 
01773 /********************************************************************************************
01774 
01775 > BOOL DocUnitList::OutputTrace(char* err,const TCHAR* TokenBuf)
01776 
01777     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01778     Created:    24/11/95
01779     Inputs:     err      = ptr to a string to appear in the trace output
01780                 TokenBuf = ptr to buffer holding last token read
01781     Outputs:    -
01782     Returns:    -
01783     Purpose:    Helper funtion for the token-reading functions
01784     SeeAlso:    -
01785 
01786 ********************************************************************************************/
01787 
01788 void DocUnitList::OutputTrace( char *err, const TCHAR *TokenBuf )
01789 {
01790 #if 0 != wxUSE_UNICODE
01791     size_t              cch = camMbstowcs( NULL, err, 0 ) + 1;
01792     wchar_t            *pwsz = (wchar_t *)alloca( cch * 2 );
01793     camMbstowcs( pwsz, err, cch );
01794     
01795     TRACE( pwsz );
01796 #else
01797     TRACE( err );
01798 #endif
01799     
01800     TRACE( _T(", but got %s\n"), TokenBuf );
01801 }
01802 
01803 /********************************************************************************************
01804 
01805 > BOOL DocUnitList::ReadLong(CCLexFile& file,void* pLong,char* err)
01806 
01807     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01808     Created:    24/11/95
01809     Inputs:     file = file to read INT32 value from
01810                 pLong = ptr to place to store the INT32 value
01811                 err   = ptr to a string to appear in the trace output if things go wrong
01812     Outputs:    *pLong = INT32 value read
01813     Returns:    TRUE if successful, FALSE otherwise
01814     Purpose:    Reads a INT32 value from file and puts it in pLong.
01815                 If it fails, err is passed to OutputTrace() and FALSE is returned
01816 
01817                 Note: pLong is a void* so that any INT32 type var can be passed in, like enum types.
01818     SeeAlso:    -
01819 
01820 ********************************************************************************************/
01821 
01822 BOOL DocUnitList::ReadLong(CCLexFile& file,void* pLong,char* err)
01823 {
01824     ERROR2IF(pLong == NULL,FALSE,"pLong == NULL");
01825 
01826     const TCHAR        *TokenBuf = file.GetTokenBuf();
01827     BOOL ok = file.GetSimpleToken();
01828     if (ok)
01829         ok = ( camSscanf( TokenBuf, _T("%li"), pLong ) == 1 );
01830 
01831     if (!ok)
01832         OutputTrace( err, TokenBuf );
01833 
01834     return ok;
01835 }
01836 
01837 /********************************************************************************************
01838 
01839 > BOOL DocUnitList::ReadDouble(CCLexFile& file,double* pDouble,char* err)
01840 
01841     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01842     Created:    24/11/95
01843     Inputs:     file    = file to read INT32 value from
01844                 pDouble = ptr to place to store the double value
01845                 err     = ptr to a string to appear in the trace output if things go wrong
01846     Outputs:    *pDouble  = double value read
01847     Returns:    TRUE if successful, FALSE otherwise
01848     Purpose:    Reads a double value from file and puts it in pDouble.
01849                 If it fails, err is passed to OutputTrace() and FALSE is returned
01850     SeeAlso:    -
01851 
01852 ********************************************************************************************/
01853 
01854 BOOL DocUnitList::ReadDouble(CCLexFile& file,double* pDouble,char* err)
01855 {
01856     ERROR2IF(pDouble == NULL,FALSE,"pDouble == NULL");
01857 
01858     const TCHAR         *TokenBuf = file.GetTokenBuf();
01859     BOOL                ok = file.GetSimpleToken();
01860     if (ok)
01861         ok = ( camSscanf( TokenBuf, _T("%lg"), pDouble ) == 1 );
01862 
01863     if (!ok)
01864         OutputTrace( err, TokenBuf );
01865 
01866     return ok;
01867 }
01868 
01869 /********************************************************************************************
01870 
01871 > BOOL DocUnitList::ReadString(CCLexFile& file,StringBase* pStr,char* err)
01872 
01873     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01874     Created:    24/11/95
01875     Inputs:     file = file to read INT32 value from
01876                 pStr = ptr to place to store the string 
01877                 err  = ptr to a string to appear in the trace output if things go wrong
01878     Outputs:    *pStr = string value read
01879     Returns:    TRUE if successful, FALSE otherwise
01880     Purpose:    Reads a string from file and puts it in pStr.
01881                 If it fails, err is passed to OutputTrace() and FALSE is returned
01882     SeeAlso:    -
01883 
01884 ********************************************************************************************/
01885 
01886 BOOL DocUnitList::ReadString(CCLexFile& file,StringBase* pStr,char* err)
01887 {
01888     ERROR2IF(pStr == NULL,FALSE,"pStr == NULL");
01889 
01890     const TCHAR        *TokenBuf = file.GetTokenBuf();
01891     BOOL                ok = file.GetSimpleToken();
01892     if (ok)
01893     {
01894         pStr->Empty();
01895         INT32 len = pStr->MaxLength();
01896         if (len > 0)
01897         {
01898             TCHAR      *pBuf = *pStr;
01899             INT32           i;
01900             for ( i = 0; TBYTE(TokenBuf[i]) > TBYTE(' ') && i < len; i++ )
01901                 pBuf[i] = TokenBuf[i];
01902 
01903             pBuf[i] = 0;
01904         }
01905     }
01906 
01907     if (!ok) OutputTrace(err,TokenBuf);
01908 
01909     return ok;
01910 }       
01911 
01912 /********************************************************************************************
01913 
01914 > BOOL DocUnitList::ReadUnitsFromFile(CCLexFile& file)
01915 
01916     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01917     Created:    23/11/95
01918     Inputs:     file = file that contains the unit definitions
01919     Outputs:    -
01920     Returns:    TRUE if OK, FALSE otherwise
01921     Purpose:    Reads the unit definitions from the given file
01922     SeeAlso:    -
01923 
01924 ********************************************************************************************/
01925 
01926 BOOL DocUnitList::ReadUnitsFromFile(CCLexFile& file)
01927 {
01928     BOOL finished = FALSE;
01929     BOOL ok;;   
01930     
01931     // Initialise lexing routines, and aspects of the lexer
01932     ok = file.InitLexer();
01933     file.SetDelimiters("\r\n");         // Set token delimiting characters
01934     file.SetCommentMarker(';');         // Set comment marker char
01935     file.SetWhitespace(" \t");          // Set whitespace chars
01936     file.SetStringDelimiters("\"\"");   // Set string delimiters
01937 
01938     UnTokenIndex Token;
01939     const TCHAR        *TokenBuf = file.GetTokenBuf();  // Token buffer remains constant until lexer deinitialisation
01940     
01941     while (ok && !finished)
01942     {
01943         // Grab a token
01944         ok = file.GetSimpleToken();
01945 
01946         // Look the token up in our table
01947         Token = FindToken( TokenBuf );
01948 
01949         switch (Token)
01950         {
01951             case TOKEN_UNIT:
01952             {
01953                 Unit* pUnit;
01954                 // Defining a unit.  Firstly make a new blank unit to put the definition in
01955                 if (MakeNewUnit(&pUnit,FALSE))
01956                 {
01957                     // We have a blank unit, now read its definition fields
01958 
01959                     double NumMillipoints;
01960                     String_32 NameStr;
01961                     String_32 SpecifierStr;
01962                     UnitType TheUnitType,BaseUnitType;
01963                     BOOL Prefix;
01964                     double BaseNumerator,BaseDenominator;
01965 
01966                     // Read in all the fields of the unit definition
01967                     if (ok) ok = ReadLong(  file,&TheUnitType,      "Expected the unit's type");
01968                     if (ok) ok = ReadString(file,&NameStr,          "Expected the unit's name");
01969                     if (ok) ok = ReadString(file,&SpecifierStr,     "Expected the unit's specifier");
01970                     if (ok) ok = ReadDouble(file,&NumMillipoints,   "Expected the unit's millipoint value");
01971                     if (ok) ok = ReadLong(  file,&Prefix,           "Expected the unit's prefix flag");
01972                     if (ok) ok = ReadLong(  file,&BaseUnitType,     "Expected the unit's base type");
01973                     if (ok) ok = ReadDouble(file,&BaseNumerator,    "Expected the unit's base numerator");
01974                     if (ok) ok = ReadDouble(file,&BaseDenominator,  "Expected the unit's base denominator");
01975 
01976                     if (ok)
01977                     {
01978                         // If it's based on another unit, get a pointer to the base unit
01979                         Unit* pBaseUnit = NULL;
01980                         if (BaseUnitType != UNIT_NOTYPE)
01981                             pBaseUnit = FindUnit(BaseUnitType);
01982 
01983                         // If no base unit AND no millipoint value, error
01984                         if (pBaseUnit == NULL && NumMillipoints <= 0.0)
01985                         {
01986                             TRACE( _T("Base unit not found AND the number of millipoints <= 0.0\n"));
01987                             TRACE( _T("Either the base unit is not yet defined, or the millipoint value is wrong\n"));
01988                             ok= FALSE;
01989                         }
01990                         else
01991                         {
01992                             if (pBaseUnit != NULL)
01993                             {
01994                                 // If Millipoint value is based on another, calculate it
01995                                 // (error if denominator is 0 - we don't want to divide by this value)
01996                                 if (BaseDenominator != 0.0)
01997                                     NumMillipoints = (pBaseUnit->GetMillipoints()*BaseNumerator)/BaseDenominator;
01998                                 else
01999                                 {
02000                                     TRACE( _T("Base denominator is 0\n"));
02001                                     ok = FALSE;
02002                                 }
02003                             }
02004 
02005                             // If we still have a silly millipoint value, error
02006                             if (NumMillipoints <= 0.0)
02007                             {
02008                                 TRACE( _T("The millipoint value is <= 0.0\n"));
02009                                 ok = FALSE;
02010                             }
02011 
02012                             if (ok)
02013                             {
02014                                 // Apply the read values
02015                                 pUnit->SetUnitType(TheUnitType);
02016                                 pUnit->SetDefaultState(TRUE);
02017                                 pUnit->SetPrefixState(Prefix);
02018                                 pUnit->SetBaseUnitType(BaseUnitType);
02019 
02020                                 pUnit->SetBaseNumerator(BaseNumerator);
02021                                 pUnit->SetBaseDenominator(BaseDenominator);
02022                                 pUnit->SetMillipoints(NumMillipoints);
02023 
02024                                 if (ok)
02025                                 {
02026                                     ok = pUnit->SetToken(NameStr);
02027                                     if (!ok) TRACE( _T("There's a problem with the name string : %s\n"),(TCHAR*)NameStr);
02028                                 }
02029 
02030                                 if (ok)
02031                                 {
02032                                     ok = pUnit->SetSpecifier(SpecifierStr);
02033                                     if (!ok) TRACE( _T("There's a problem with the specifier string : %s\n"),(TCHAR*)NameStr);
02034                                 }
02035                             }
02036                         }
02037                     }
02038                 }
02039             }
02040             break;
02041 
02042             case TOKEN_PAGEUNITS:
02043             {
02044                 UnitType TheUnitType;
02045                 if (ok) ok = ReadLong(file,&TheUnitType,"Expected the Page unit's type");
02046 
02047                 if (ok)
02048                 {
02049                     ok = (FindUnit(TheUnitType) != NULL);
02050                     if (!ok) TRACE( _T("The PageUnit specified cannot be found\n"));
02051                 }                   
02052 
02053                 if (ok) SetPageUnits(TheUnitType);
02054             }
02055             break;
02056 
02057             case TOKEN_FONTUNITS:
02058             {
02059                 UnitType TheUnitType;
02060                 if (ok) ok = ReadLong(file,&TheUnitType,"Expected the Font unit's type");
02061                 if (ok)
02062                 {
02063                     ok = (FindUnit(TheUnitType) != NULL);
02064                     if (!ok) TRACE( _T("The FontUnit specified cannot be found\n"));
02065                 }                   
02066                 if (ok) SetFontUnits(TheUnitType);
02067             }
02068             break;
02069 
02070             case TOKEN_UNITSEND:
02071                 finished = TRUE;
02072                 break;
02073 
02074             default:
02075                 TRACE( _T("DocUnitList: Unexpected token - %s\n"),TokenBuf);
02076                 break;
02077         }
02078     }
02079 
02080     if (!ok)
02081     {
02082         TRACE( _T("\nDocUnitList: Offending line - %s\n"),file.GetLineBuf());
02083         ERROR3("Error reading units.  See TRACE output for details");
02084     }
02085 
02086     // We are now finished with the lexer
02087     file.DeinitLexer();
02088 
02089     return (ok);
02090 }
02091 
02092 /********************************************************************************************
02093 
02094 >   BOOL DocUnitList::MakeFactoryDefaultUnits()
02095 
02096     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02097     Created:    5/7/94
02098     Inputs:     -
02099     Outputs:    -
02100     Returns:    TRUE  - successfully added all default units to the doc unit list
02101                 FALSE - Can't add all the units to the list (lack of memory most likely)
02102     Purpose:    Defines all the default units for a document and places them on the list.
02103                 Called early on in the document initialisation routines.
02104                 NOTE: Added some ERROR2 checks so that problems in the default units can be
02105                 trapped early on rather than a lot later. Should not normally go off unless
02106                 some of the error checking has problems.
02107 
02108                 (Markn 23/11/95 - The name of this function has changed so that it is no longer the
02109                 routine called by the document initialisation code)
02110 
02111     Errors:     Can only be called once per instance. Errors if called again.
02112 
02113 ********************************************************************************************/
02114 
02115 BOOL DocUnitList::MakeFactoryDefaultUnits()
02116 {
02117     // Remove all previously defined units.  We're starting from scratch
02118     DeleteAll();
02119 
02120     Unit* pUnit = NULL;
02121     BOOL ok = TRUE;
02122 
02123     // Default unit - Millimetres
02124     if (MakeNewUnit(&pUnit,FALSE))
02125     {
02126         String_32 TokenStr(_R(IDS_MILLIMETRES));
02127         String_32 SpecifierStr(_R(IDS_MM));
02128 
02129         pUnit->SetDefaultState(TRUE);
02130         pUnit->SetPrefixState(FALSE);
02131         pUnit->SetUnitType(MILLIMETRES);
02132 
02133 
02134         ok =    pUnit->SetToken(TokenStr) &&
02135                 pUnit->SetSpecifier(SpecifierStr) &&
02136                 pUnit->SetBaseUnitType(NOTYPE) &&
02137                 pUnit->SetMillipoints(MM_MP_VAL);
02138              
02139         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad MILLIMETRES");
02140     }
02141     else
02142         return FALSE;
02143 
02144     // Default unit - Centimetres
02145     if (MakeNewUnit(&pUnit,FALSE))
02146     {
02147         String_32 TokenStr(_R(IDS_CENTIMETRES));
02148         String_32 SpecifierStr(_R(IDS_CM));
02149 
02150         pUnit->SetUnitType(CENTIMETRES);
02151         pUnit->SetDefaultState(TRUE);
02152         pUnit->SetPrefixState(FALSE);
02153         pUnit->SetBaseUnitType(MILLIMETRES);
02154 
02155         ok =    pUnit->SetBaseNumerator(10) &&
02156                 pUnit->SetBaseDenominator(1) &&
02157                 pUnit->SetMillipoints(CM_MP_VAL) &&
02158                 pUnit->SetToken(TokenStr) &&
02159                 pUnit->SetSpecifier(SpecifierStr);
02160 
02161         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad CENTIMETRES");
02162     }
02163     else
02164         return FALSE;
02165 
02166     // Default unit - Metres
02167     if (MakeNewUnit(&pUnit,FALSE))
02168     {
02169         String_32 TokenStr(_R(IDS_METRES));
02170         String_32 SpecifierStr(_R(IDS_M));
02171 
02172         pUnit->SetUnitType(METRES);
02173         pUnit->SetDefaultState(TRUE);
02174         pUnit->SetPrefixState(FALSE);
02175         pUnit->SetBaseUnitType(CENTIMETRES);
02176         
02177         ok =    pUnit->SetBaseNumerator(100) &&
02178                 pUnit->SetBaseDenominator(1) &&
02179                 pUnit->SetMillipoints(M_MP_VAL) &&
02180                 pUnit->SetToken(TokenStr) &&
02181                 pUnit->SetSpecifier(SpecifierStr);
02182         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad METRES");
02183     }
02184     else
02185         return FALSE;
02186 
02187     // Default unit - Kilometres
02188     if (MakeNewUnit(&pUnit,FALSE))
02189     {
02190         String_32 TokenStr(_R(IDS_KILOMETRES));
02191         String_32 SpecifierStr(_R(IDS_KM));
02192 
02193         pUnit->SetUnitType(KILOMETRES);
02194         pUnit->SetDefaultState(TRUE);
02195         pUnit->SetPrefixState(FALSE);
02196         pUnit->SetBaseUnitType(METRES);
02197         ok =    pUnit->SetBaseNumerator(1000) &&
02198                 pUnit->SetBaseDenominator(1) &&
02199                 pUnit->SetMillipoints(KM_MP_VAL) &&
02200                 pUnit->SetToken(TokenStr) &&
02201                 pUnit->SetSpecifier(SpecifierStr);
02202         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad KILOMETRES");
02203     }
02204     else
02205         return FALSE;
02206 
02207     // Default unit - Millipoints
02208     if (MakeNewUnit(&pUnit,FALSE))
02209     {
02210         String_32 TokenStr(_R(IDS_MILLIPOINTS));
02211         String_32 SpecifierStr(_R(IDS_MP));
02212 
02213         pUnit->SetUnitType(MILLIPOINTS);
02214         pUnit->SetDefaultState(TRUE);
02215         pUnit->SetPrefixState(FALSE);
02216         pUnit->SetBaseUnitType(NOTYPE);
02217         ok =    pUnit->SetMillipoints(MP_MP_VAL) &&
02218                 pUnit->SetToken(TokenStr) &&
02219                 pUnit->SetSpecifier(SpecifierStr);
02220         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad MILLIPOINTS");
02221     }
02222     else
02223         return FALSE;
02224 
02225     // Default unit - Computer points
02226     if (MakeNewUnit(&pUnit,FALSE))
02227     {
02228         String_32 TokenStr(_R(IDS_COMP_POINTS));
02229         String_32 SpecifierStr(_R(IDS_PT));
02230 
02231         pUnit->SetUnitType(COMP_POINTS);
02232         pUnit->SetDefaultState(TRUE);
02233         pUnit->SetPrefixState(FALSE);
02234         pUnit->SetBaseUnitType(MILLIPOINTS);
02235         ok =    pUnit->SetBaseNumerator(1000) &&
02236                 pUnit->SetBaseDenominator(1) &&
02237                 pUnit->SetMillipoints(PT_MP_VAL) &&
02238                 pUnit->SetToken(TokenStr) &&
02239                 pUnit->SetSpecifier(SpecifierStr);
02240         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad COMP_POINTS");
02241     }
02242     else
02243         return FALSE;
02244 
02245     // Default unit - Picas
02246     if (MakeNewUnit(&pUnit,FALSE))
02247     {
02248         String_32 TokenStr(_R(IDS_PICAS));
02249         String_32 SpecifierStr(_R(IDS_PI));
02250 
02251         pUnit->SetUnitType(PICAS);
02252         pUnit->SetDefaultState(TRUE);
02253         pUnit->SetPrefixState(FALSE);
02254         pUnit->SetBaseUnitType(COMP_POINTS);
02255         ok =    pUnit->SetBaseNumerator(12) &&
02256                 pUnit->SetBaseDenominator(1) &&
02257                 pUnit->SetMillipoints(PI_MP_VAL) &&
02258                 pUnit->SetToken(TokenStr) &&
02259                 pUnit->SetSpecifier(SpecifierStr);
02260         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad PICAS");
02261     }
02262     else
02263         return FALSE;
02264 
02265     // Default unit - Inches
02266     if (MakeNewUnit(&pUnit,FALSE))
02267     {
02268         String_32 TokenStr(_R(IDS_INCHES));
02269         String_32 SpecifierStr(_R(IDS_IN));
02270 
02271         pUnit->SetUnitType(INCHES);
02272         pUnit->SetDefaultState(TRUE);
02273         pUnit->SetPrefixState(FALSE);
02274         pUnit->SetBaseUnitType(PICAS);
02275         ok =    pUnit->SetBaseNumerator(6) &&
02276                 pUnit->SetBaseDenominator(1) &&
02277                 pUnit->SetMillipoints(IN_MP_VAL) &&
02278                 pUnit->SetToken(TokenStr) &&
02279                 pUnit->SetSpecifier(SpecifierStr);
02280         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad INCHES");
02281     }
02282     else
02283         return FALSE;
02284 
02285     // Default unit - Feet
02286     if (MakeNewUnit(&pUnit,FALSE))
02287     {
02288         String_32 TokenStr(_R(IDS_FEET));
02289         String_32 SpecifierStr(_R(IDS_FT));
02290 
02291         pUnit->SetUnitType(FEET);
02292         pUnit->SetDefaultState(TRUE);
02293         pUnit->SetPrefixState(FALSE);
02294         pUnit->SetBaseUnitType(INCHES);
02295         ok =    pUnit->SetBaseNumerator(12) &&
02296                 pUnit->SetBaseDenominator(1) &&
02297                 pUnit->SetMillipoints(FT_MP_VAL) &&
02298                 pUnit->SetToken(TokenStr) &&
02299                 pUnit->SetSpecifier(SpecifierStr);
02300         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad FEET");
02301     }
02302     else
02303         return FALSE;
02304 
02305     // Default unit - Yards
02306     if (MakeNewUnit(&pUnit,FALSE))
02307     {
02308         String_32 TokenStr(_R(IDS_YARDS));
02309         String_32 SpecifierStr(_R(IDS_YD));
02310 
02311         pUnit->SetUnitType(YARDS);
02312         pUnit->SetDefaultState(TRUE);
02313         pUnit->SetPrefixState(FALSE);
02314         pUnit->SetBaseUnitType(FEET);
02315         ok =    pUnit->SetBaseNumerator(3) &&
02316                 pUnit->SetBaseDenominator(1) &&
02317                 pUnit->SetMillipoints(YD_MP_VAL) &&
02318                 pUnit->SetToken(TokenStr) &&
02319                 pUnit->SetSpecifier(SpecifierStr);
02320         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad YARDS");
02321     }
02322     else
02323         return FALSE;
02324 
02325     // Default unit - Miles
02326     if (MakeNewUnit(&pUnit,FALSE))
02327     {
02328         String_32 TokenStr(_R(IDS_MILES));
02329         String_32 SpecifierStr(_R(IDS_MI));
02330 
02331         pUnit->SetUnitType(MILES);
02332         pUnit->SetDefaultState(TRUE);
02333         pUnit->SetPrefixState(FALSE);
02334         pUnit->SetBaseUnitType(YARDS);
02335         ok =    pUnit->SetBaseNumerator(1760) &&
02336                 pUnit->SetBaseDenominator(1) &&
02337                 pUnit->SetMillipoints(MI_MP_VAL) &&
02338                 pUnit->SetToken(TokenStr) &&
02339                 pUnit->SetSpecifier(SpecifierStr);
02340         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad MILES");
02341     }
02342     else
02343         return FALSE;
02344 
02345     // Default unit - Pixels
02346     if (MakeNewUnit(&pUnit,FALSE))
02347     {
02348         String_32 TokenStr(_R(IDS_PIXELS));
02349         String_32 SpecifierStr(_R(IDS_PX));
02350 
02351         pUnit->SetDefaultState(TRUE);
02352         pUnit->SetPrefixState(FALSE);
02353         pUnit->SetUnitType(PIXELS);
02354 
02355 
02356         ok =    pUnit->SetToken(TokenStr) &&
02357                 pUnit->SetSpecifier(SpecifierStr) &&
02358                 pUnit->SetBaseUnitType(NOTYPE) &&
02359                 pUnit->SetMillipoints(PX_MP_VAL);
02360              
02361         ERROR2IF(!ok,FALSE,"DocUnitList::MakeFactoryDefaultUnits bad PIXELS");
02362     }
02363     else
02364         return FALSE;
02365     
02366     return TRUE;
02367 }

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