// $Id: colcomp.cpp 1315 2006-06-14 09:51:34Z alex $
/* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
================================XARAHEADERSTART===========================
 
               Xara LX, a vector drawing and manipulation program.
                    Copyright (C) 1993-2006 Xara Group Ltd.
       Copyright on certain contributions may be held in joint with their
              respective authors. See AUTHORS file for details.

LICENSE TO USE AND MODIFY SOFTWARE
----------------------------------

This file is part of Xara LX.

Xara LX is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as published
by the Free Software Foundation.

Xara LX and its component source files are distributed in the hope
that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with Xara LX (see the file GPL in the root directory of the
distribution); if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA  02110-1301 USA


ADDITIONAL RIGHTS
-----------------

Conditional upon your continuing compliance with the GNU General Public
License described above, Xara Group Ltd grants to you certain additional
rights. 

The additional rights are to use, modify, and distribute the software
together with the wxWidgets library, the wxXtra library, and the "CDraw"
library and any other such library that any version of Xara LX relased
by Xara Group Ltd requires in order to compile and execute, including
the static linking of that library to XaraLX. In the case of the
"CDraw" library, you may satisfy obligation under the GNU General Public
License to provide source code by providing a binary copy of the library
concerned and a copy of the license accompanying it.

Nothing in this section restricts any of the rights you have under
the GNU General Public License.


SCOPE OF LICENSE
----------------

This license applies to this program (XaraLX) and its constituent source
files only, and does not necessarily apply to other Xara products which may
in part share the same code base, and are subject to their own licensing
terms.

This license does not apply to files in the wxXtra directory, which
are built into a separate library, and are subject to the wxWindows
license contained within that directory in the file "WXXTRA-LICENSE".

This license does not apply to the binary libraries (if any) within
the "libs" directory, which are subject to a separate license contained
within that directory in the file "LIBS-LICENSE".


ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
----------------------------------------------

Subject to the terms of the GNU Public License (see above), you are
free to do whatever you like with your modifications. However, you may
(at your option) wish contribute them to Xara's source tree. You can
find details of how to do this at:
  http://www.xaraxtreme.org/developers/

Prior to contributing your modifications, you will need to complete our
contributor agreement. This can be found at:
  http://www.xaraxtreme.org/developers/contribute/

Please note that Xara will not accept modifications which modify any of
the text between the start and end of this header (marked
XARAHEADERSTART and XARAHEADEREND).


MARKS
-----

Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
designs are registered or unregistered trademarks, design-marks, and/or
service marks of Xara Group Ltd. All rights in these marks are reserved.


      Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
                        http://www.xara.com/

=================================XARAHEADEREND============================
 */

// The document component for the document's colour list.

/*
*/

#include "camtypes.h"

#include "colcomp.h"

//#include "basedoc.h" - in camtypes.h [AUTOMATICALLY REMOVED]
//#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
#include "collist.h"
#include "colormgr.h"
//#include "colmodel.h" - in camtypes.h [AUTOMATICALLY REMOVED]
#include "aw_eps.h"
#include "cameleps.h"
//#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
#include "ccdc.h"
#include "colourix.h"
//#include "doccolor.h" - in camtypes.h [AUTOMATICALLY REMOVED]
//#include "tim.h"
//#include "resource.h"
//#include "grndrgn.h"
#include "impcol.h"
//#include "jason.h"
#include "unicdman.h"
//#include "sgcolour.h"

//#include "camfiltr.h"	// BaseCamelotFilter - version 2 native filter - in camtypes.h [AUTOMATICALLY REMOVED]
#include "cxftags.h"	// TAG_DEFINERGBCOLOUR TAG_DEFINECOMPLEXCOLOUR
//#include "cxfdefs.h"	// SIZE_DEFINERGBCOLOUR SIZE_DEFINECOMPLEXCOLOUR - in camtypes.h [AUTOMATICALLY REMOVED]
#include "cxfcols.h"	// REF_DEFAULTCOLOUR_TRANSPARENT
#include "cxfile.h"		// CXF_UNKNOWN_SIZE
#include "expcol.h"		// ExportedColours handling class
//#include "cxfrec.h"		// CXaraFileRecord handler - in camtypes.h [AUTOMATICALLY REMOVED]
//#include "filtrres.h"	// _R(IDS_NATIVE_COLOURWARNING)

DECLARE_SOURCE("$Revision: 1315 $");

// Declare smart memory handling in Debug builds
#define new CAM_DEBUG_NEW

CC_IMPLEMENT_DYNAMIC(ColourListComponentClass, 	DocComponentClass)
CC_IMPLEMENT_DYNAMIC(ColourListComponent, 		DocComponent)

// The error limit to use when comparing colour definitions
#define COL_ACCURACY (0.00001)

// This is our special linked value for native/web files
const FIXED24 LinkValue = FIXED24(-8.0);

// If we do no load a colour definition, then this is the colour that we will use instead
#define REPLACEMENTCOLOUR COLOUR_BLACK

// WEBSTER - markn 14/2/97
// Introduced WEBSTER_IGNORE_NAME_MATCHING so that Webster can ignore the name when
// trying to find an identical colour
// Set to FALSE if you want it to behave the same as v1.5
#ifndef WEBSTER
#define WEBSTER_IGNORE_NAME_MATCHING FALSE
#else
#define WEBSTER_IGNORE_NAME_MATCHING TRUE
#endif // WEBSTER

/********************************************************************************************
********************************************************************************************/

/********************************************************************************************

>	BOOL ColourListComponentClass::Init()

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	02/08/94
	Returns:	TRUE if all went well;
				FALSE if not.
	Purpose:	Register the colour list document component with the main application.
	Errors:		Out of memory.
	SeeAlso:	DocComponent

********************************************************************************************/

BOOL ColourListComponentClass::Init()
{
	// Instantiate a component class to register with the application.
	ColourListComponentClass *pClass = new ColourListComponentClass;
	if (pClass == NULL)
		return FALSE;

	// Register it
	GetApplication()->RegisterDocComponent(pClass);

	// All ok
	return TRUE;
}


/********************************************************************************************

>	BOOL ColourListComponentClass::AddComponent(BaseDocument *pDocument)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	02/08/94
	Inputs:		pDocument - the document to add the colour list to.
	Returns:	TRUE if the colour list was added ok;
				FALSE if not.
	Purpose:	Add a colour list component to the specified document.
	Errors:		Out of memory
	SeeAlso:	ColourListComponentClass

********************************************************************************************/

BOOL ColourListComponentClass::AddComponent(BaseDocument *pDocument)
{
	// Check to see if this document already has a colour list; if so, leave it alone.
	if (pDocument->GetDocComponent(CC_RUNTIME_CLASS(ColourListComponent)) != NULL)
		return TRUE;

	// No colour list - try to create a new one for this document.
	ColourList *pList = new ColourList;
	if(pList == NULL)
		return FALSE;

	pList->Init( pDocument );		// Let the ColourList know what its parent document is

	// Ok - create the colour list component using this list.
	ColourListComponent *pComponent = new ColourListComponent(pList);
	if (pComponent == NULL)
	{
		// Out of memory...
		delete pList;
		return FALSE;
	}

	// All ok - add the component to the document.
	pDocument->AddDocComponent(pComponent);
	return true;
}



/********************************************************************************************

>	ColourListComponent::ColourListComponent()

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	8/11/94
	Purpose:	Construct a colour list component. DO NOT use this constructor. It gives
				and ERROR3 (and sets up this in a semi-safe default state)
	SeeAlso:	ColourListComponent

********************************************************************************************/

ColourListComponent::ColourListComponent()
{
	ERROR3("ColourListComponent constructed with default constructor!?\n");
	
	// We don't have a colour list! Eek!
	pIndexedColours = NULL;

	// Initialise importer colour maps etc
	pNewColours	= NULL;

	// Initialise Exporter colour list
	pExportedColours = NULL;
	
	// Initialise IndexedColour ComponentCopy array pointers
	SourceColours	= NULL;
	DestColours		= NULL;
	ColourTableSize	= 32;

	// Our link to the BaseCamelotFilter
	pCamFilter = NULL;
	// Set our variable so that we warn about a possible replacement only once
	WarnedBefore = FALSE;
}



/********************************************************************************************

>	ColourListComponent::ColourListComponent(ColourList *pColList)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	02/08/94
	Inputs:		pColList - the colour list to use for this colour list componet.
	Purpose:	Construct a colour list component using the given colour list.

	Notes:		NOTE that the list you pass in now "belongs" to this CLC, and it
				will be automatically deleted when you delete this CLC object.

	Errors:		ENSURE if pColList is NULL.
	SeeAlso:	ColourListComponent

********************************************************************************************/

ColourListComponent::ColourListComponent(ColourList *pColList)
{
	ENSURE(pColList != NULL, "NULL colour list in colour list component constructor!");

	// Install this colour list.
	pIndexedColours = pColList;

	// Initialise importer colour tables etc
	pNewColours	= NULL;

	// Initialise Exporter colour list
	pExportedColours = NULL;

	// Initialise IndexedColour ComponentCopy array pointers
	SourceColours	= NULL;
	DestColours		= NULL;
	ColourTableSize	= 32;

	// Our link to the BaseCamelotFilter
	pCamFilter = NULL;
	// Set our variable so that we warn about a possible replacement only once
	WarnedBefore = FALSE;
}

/********************************************************************************************

>	ColourListComponent::~ColourListComponent()

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	08/09/94
	Purpose:	Clean up a colour list component's data structures - deletes the colour
				list.
	Errors:		ENSURE if IndexedColour copying stuff has not been cleaned up (this will
				occur if End/AbortComponentCopy is not called after a component copy)
	SeeAlso:	ColourListComponent

********************************************************************************************/

ColourListComponent::~ColourListComponent()
{
	// Delete our colour list.
	if (pIndexedColours != NULL)
	{
		pIndexedColours->DeleteAll();

		delete pIndexedColours;
		pIndexedColours = NULL;
	}

	// Sanity check to see if we've done something terrible...
	ENSURE(SourceColours == NULL && DestColours == NULL,
			"Someone failed to EndComponentCopy before destructing a ColourListComponent");

	// As we have finished with it now, destroy the list of exported colours
	if (pExportedColours)
	{
		delete pExportedColours;
		pExportedColours = NULL;
	}
}

/********************************************************************************************
********************************************************************************************/

// Saving/loading code for the new native/web file format

/********************************************************************************************
********************************************************************************************/

/********************************************************************************************

>	BOOL ColourListComponent::StartImport(BaseCamelotFilter *pFilter)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/5/96
	Inputs:		pFilter - the BaseCamelotFilter filter that is being used to import a file.
	Returns:	TRUE if the component was able to prepare for importing;
				FALSE if not (e.g. out of memory)
	Purpose:	Inform the colour list document component that a Native or Web import is
				about to start.
	SeeAlso:	DocComponent

********************************************************************************************/

BOOL ColourListComponent::StartImport(BaseCamelotFilter *pFilter)
{
TRACEUSER( "Neville",_T("ColourListComponent::StartImport\n") );
	if (pFilter == NULL)
	{
		ERROR3("ColourListComponent::StartImport filter is null!");
		return TRUE;
	}

	// Save this in our link to the BaseCamelotFilter
	pCamFilter = pFilter;
	// Set our variable so that we warn about a possible replacement only once
	WarnedBefore = FALSE;
	
	// Get a colour table and don't do strict checking (as per Camelot EPS and Native EPS).
	pNewColours = new ImportedColours(this, FALSE);
	if ((pNewColours == NULL) || !pNewColours->Init())
		return FALSE;

	// We keep a record of how nested we are with respect to linking colours, e.g.
	// links of links of links.
	// A nesting of 0 is no nesting.
	// Do this so that we are consistent with the EPS form
	LinkNesting = 0;

	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::EndImport(BaseCamelotFilter *pFilter, BOOL Success)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/5/96
	Inputs:		pFilter - the BaseCamelotFilter filter that is being used to import a file.
				Success - TRUE => The import was successful;
						 FALSE => The import failed - abandon any changes.
	Returns:	TRUE if the component was able to end the importing;
				FALSE if not (e.g. out of memory)
	Purpose:	Inform the colour list document component that a Native or Web import has
				just finished.
	SeeAlso:	DocComponent

********************************************************************************************/

BOOL ColourListComponent::EndImport(BaseCamelotFilter *pFilter, BOOL Success)
{
TRACEUSER( "Neville", _T("ColourListComponent::EndImport\n") );
	if (pFilter == NULL)
	{
		ERROR3("ColourListComponent::EndImport filter is null!");
		return TRUE;
	}

	// If we didn't even get to initialise, then return quietly.
	if (pNewColours == NULL)
	{
		ERROR3("ColourListComponent::EndImport pNewColours is null!");
		return TRUE;
	}

	// Import is finished, so add any outstanding colours to the document (if the
	// import was successful), and delete the colour table
	if (Success)
	{
		// Try and sort the imported colour list by the entry number that was saved
		// in the colour definition on export. This was the colour's position in 
		// the indexed colour list.
		pNewColours->SortColoursByEntryNumber();
		
		// Adds the colours to the system, with undo
		pNewColours->AddColoursToDocument();
	}
	else
	{
		// Import failed - destroy all the colours.
		pNewColours->DestroyColours();
	}

	// Finally, delete the IndexedColour table.
	delete pNewColours;
	pNewColours = NULL;

	// Null our link to the BaseCamelotFilter
	pCamFilter = NULL;
	// Set our variable so that we warn about a possible replacement only once
	WarnedBefore = FALSE;

	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::GetDocColour(INT32 ColourRef, CXaraFileRecord* pCXFileRec, DocColour* pDocColour)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	30/5/96
	Inputs:		ColourRef	- The colour reference or record number that the record handler has loaded
							from the record.
	Outputs:	pDocColour	- A pointer to return the required doc colour in
	Returns:	TRUE if the colour reference was succesfully converted into a DocColour;
				FALSE if not (e.g. out of memory)
	Purpose:	Try and convert a colour reference i.e. record number into a previously
				imported colour definition which should now be an indexed colour in the document.
	SeeAlso:	ColourRecordHandler; 

********************************************************************************************/

BOOL ColourListComponent::GetDocColour(INT32 ColourRef, DocColour* pDocColour)
{
	ERROR2IF(pDocColour == NULL,FALSE,"ColourListComponent::GetDocColour NULL pCXFileRec");
	ERROR2IF(pNewColours == NULL,FALSE,"ColourListComponent::ImportSimpleColour NULL pNewColours");
//TRACEUSER( "Neville", _T("GetDocColour for ref %d\n"), ColourRef);
	
	// First check to see if the colour refers to any of the built in colours.
	// These will have negative record numbers
	if (ColourRef < 0)
	{
		// At present, we only use the one colour reference
		StockColour defaultcolour = COLOUR_NONE;
		switch (ColourRef)
		{
			case REF_DEFAULTCOLOUR_TRANSPARENT:
				defaultcolour = COLOUR_TRANS;
				break;
			case REF_DEFAULTCOLOUR_BLACK:
				defaultcolour = COLOUR_BLACK;
				break;
			case REF_DEFAULTCOLOUR_WHITE:
				defaultcolour = COLOUR_WHITE;
				break;
			case REF_DEFAULTCOLOUR_RED:
				defaultcolour = COLOUR_RED;
				break;
			case REF_DEFAULTCOLOUR_GREEN:
				defaultcolour = COLOUR_GREEN;
				break;
			case REF_DEFAULTCOLOUR_BLUE:
				defaultcolour = COLOUR_BLUE;
				break;
			case REF_DEFAULTCOLOUR_CYAN:
				defaultcolour = COLOUR_CYAN;
				break;
			case REF_DEFAULTCOLOUR_MAGENTA:
				defaultcolour = COLOUR_MAGENTA;
				break;
			case REF_DEFAULTCOLOUR_YELLOW:
				defaultcolour = COLOUR_YELLOW;
				break;
			default:
			{
				defaultcolour = REPLACEMENTCOLOUR;
				// It is an unknown default colour reference
				// We will warn the user and use a replacement colour instead
				// If we have a pFilter then ask the default warning handle to append our message
				if (pCamFilter)
				{
					if (!WarnedBefore)
					{
						pCamFilter->AppendWarning(_R(IDS_NATIVE_COLOURWARNING));
						WarnedBefore = TRUE;
					}

				}
				else
					ERROR2(FALSE,"ColourListComponent::GetDocColour negative ColourRef is unknown");
				break;
			}
		}
		
		// Make ourselves the required colour
		DocColour * pReplacementCol = new DocColour(defaultcolour);
		// Make the return colour this
		*pDocColour = *pReplacementCol;
		// And now delete that temp replacement colour
		delete pReplacementCol;
	}
	else
	{
		// In case of early exit set the return DocColour pointer to NULL, i.e. nothing found
		//*pDocColour = NULL;

		// Try and find the specified record number in our colour list
		IndexedColour *pCol = pNewColours->GetColour(ColourRef);
		// If not found then this is a problem as a colour must have been defined before its being
		// referenced 
		// We will warn the user and use a replacement colour instead
		if (pCol == NULL)
		{
			// If we have a pFilter then ask the default warning handle to append our message
			if (pCamFilter)
			{
				if (!WarnedBefore)
				{
					pCamFilter->AppendWarning(_R(IDS_NATIVE_COLOURWARNING));
					WarnedBefore = TRUE;
				}

				// Make ourselves a colour to use instead
				DocColour * pReplacementCol =  new DocColour(REPLACEMENTCOLOUR);
				// Make the return colour this
				*pDocColour = *pReplacementCol;
				// And now delete that temp replacement colour
				delete pReplacementCol;
			}
			else
				ERROR2(FALSE,"ColourListComponent::GetDocColour ColourRef cannot be found");
		}
		else
		{		
			// Make the specified DocColour referencing this IndexedColour.
			pDocColour->MakeRefToIndexedColour(pCol);
		}
	}

	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::ImportSimpleColour(CXaraFileRecord* pCXFileRec)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	30/5/96
	Inputs:		pCXFileRec - The CXaraFileRecord that is being used to provide read functions etc.
	Returns:	TRUE if the record was succesfully imported;
				FALSE if not (e.g. out of memory)
	Purpose:	Try and import a simple RGB colour definition record into the document.
	SeeAlso:	ColourRecordHandler; 

********************************************************************************************/

BOOL ColourListComponent::ImportSimpleColour(CXaraFileRecord* pCXFileRec)
{
	ERROR2IF(pCXFileRec == NULL,FALSE,"ColourListComponent::ImportSimpleColour NULL pCXFileRec");
	ERROR2IF(pNewColours == NULL,FALSE,"ColourListComponent::ImportSimpleColour NULL pNewColours");

//TRACEUSER( "Neville", _T("ImportSimpleColour\n"));
	// Read in the simple RGB colour
	BYTE Red;
	BYTE Green;
	BYTE Blue;
	BOOL ok = pCXFileRec->ReadBYTE(&Red);
	if (ok) ok = pCXFileRec->ReadBYTE(&Green);
	if (ok) ok = pCXFileRec->ReadBYTE(&Blue);

	NewColourInfo ColourInfo;
	// Flag we are importing a web/native style colour and so use the specified parent and not
	// the context form.
	ColourInfo.RecordNumber = pCXFileRec->GetRecordNumber();
	ColourInfo.WebNativeColour = TRUE;
	ColourRGBT NewRGBT;
	String_64 ColName; //(TEXT("_"));
	// Make the name unique by adding a text form of the record number 
	TCHAR			   *pNewName = (TCHAR *)ColName;
	camSnprintf( pNewName, 64, _T("_%d"), ColourInfo.RecordNumber );

	NewRGBT.Red = (double)((double)Red/256.0);	
	NewRGBT.Green = (double)((double)Green/256.0);	
	NewRGBT.Blue = (double)((double)Blue/256.0);	
	if (ok) ok = pNewColours->AddColour(&ColName, &NewRGBT, &ColourInfo);

	return ok;
}

/********************************************************************************************

>	BOOL ColourListComponent::ImportColourDefinition(CXaraFileRecord* pCXFileRec)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	28/5/96
	Inputs:		pCXFileRec - The CXaraFileRecord that is being used to provide read functions etc.
	Returns:	TRUE if the record was succesfully imported;
				FALSE if not (e.g. out of memory)
	Purpose:	Try and import a colour definition record into the document.
	SeeAlso:	ColourRecordHandler; 

********************************************************************************************/

BOOL ColourListComponent::ImportColourDefinition(CXaraFileRecord* pCXFileRec)
{
	ERROR2IF(pCXFileRec == NULL,FALSE,"ColourListComponent::ImportColourDefinition NULL pCXFileRec");
	ERROR2IF(pNewColours == NULL,FALSE,"ColourListComponent::ImportColourDefinition NULL pNewColours");
	

	// Check for special types (NB a colour cannot be both a spot colour and a linked colour).
	NewColourInfo ColourInfo;
//	BOOL Linked = FALSE;
	// Flag we are importing a web/native style colour and so use the specified parent and not
	// the context form.
	ColourInfo.RecordNumber = pCXFileRec->GetRecordNumber();
	ColourInfo.WebNativeColour = TRUE;
	//IndexedColour *pParent = NULL;

	// Read in the simple RGB colour, which we won't need
	BYTE Red;
	BYTE Green;
	BYTE Blue;
	BOOL ok = pCXFileRec->ReadBYTE(&Red);
	if (ok) ok = pCXFileRec->ReadBYTE(&Green);
	if (ok) ok = pCXFileRec->ReadBYTE(&Blue);

	// read in the colour model
	ColourModel ColModel = COLOURMODEL_RGBT;
	BYTE temp;
	if (ok) ok = pCXFileRec->ReadBYTE(&temp);
	ColModel = (ColourModel)temp;

	// read in the colour type
	ExportColourType ColType = EXPORT_COLOURTYPE_NORMAL;
	if (ok) ok = pCXFileRec->ReadBYTE(&temp);
	ColType = (ExportColourType)temp;

	// read in the entry number that this colour should be in the list of colours
	UINT32 EntryNumber = 0;
	if (ok) ok = pCXFileRec->ReadUINT32(&EntryNumber);
	ColourInfo.EntryNumber = EntryNumber;

	// read in the record number of the parent colour
	UINT32 ParentColour = 0;
	if (ok) ok = pCXFileRec->ReadUINT32(&ParentColour);
	// Now convert this into a indexed colour pointer, if required
	if (ok && (ColType == EXPORT_COLOURTYPE_LINKED || ColType == EXPORT_COLOURTYPE_TINT ||
		ColType == EXPORT_COLOURTYPE_SHADE))
	{
		TRACEUSER( "Neville", _T("Trying to find parent reference %d\n"),ParentColour);
		ColourInfo.pParentCol = pNewColours->GetColour(ParentColour);
		if (ColourInfo.pParentCol == NULL)
		{
			TRACEUSER( "Neville", _T("Cannot convert parent colour reference %d into an IndexedColour\n"),ParentColour);
			ERROR2(FALSE,"Cannot find parent IndexedColour");
		}
	}

	// Read in the four colour components
	UINT32 Comp1 = 0;
	if (ok) ok = pCXFileRec->ReadUINT32(&Comp1);
	UINT32 Comp2 = 0;
	if (ok) ok = pCXFileRec->ReadUINT32(&Comp2);
	UINT32 Comp3 = 0;
	if (ok) ok = pCXFileRec->ReadUINT32(&Comp3);
	UINT32 Comp4 = 0;
	if (ok) ok = pCXFileRec->ReadUINT32(&Comp4);
	
	String_64 ColName; 
	if (ok) ok = pCXFileRec->ReadUnicode(&ColName);//, ColName.MaxLength());
	
	if (ColName.Length() == 0 )
	{	
		// We are an unnamed colour and so make up a name based on the record number
		// This is so that all the existing import code can be reused.
		// Make the name unique by adding a text form of the record number 
		TCHAR		   *pNewName = (TCHAR *)ColName;
		camSnprintf( pNewName, 64, _T("_%d"), ColourInfo.RecordNumber );
	}
TRACEUSER( "Neville", _T("ImportColourDefinition Name %s RecordNumber %d, EntryNumber %d\n"),(TCHAR*)ColName,ColourInfo.RecordNumber,EntryNumber);
	
	// We had a problem reading the colour definition so stop now
	if (!ok)
		return FALSE;

	// Read the colour components according to the colour model.
	switch (ColType)
	{
		case EXPORT_COLOURTYPE_NORMAL:
				// Set the correct colour type
				ColourInfo.Type = COLOURTYPE_NORMAL;
				// Fall through below
		case EXPORT_COLOURTYPE_SPOT:
		case EXPORT_COLOURTYPE_LINKED:
			// Set the correct colour type
			if (ColType == EXPORT_COLOURTYPE_SPOT)
				ColourInfo.Type = COLOURTYPE_SPOT;
			else if (ColType == EXPORT_COLOURTYPE_LINKED)
				ColourInfo.Type = COLOURTYPE_LINKED;

			// These all require the same handling
			// Linked colours save out the components in the normal fashion
			switch (ColModel)
			{
				case COLOURMODEL_RGBT:
					{
						ColourRGBT NewRGBT;
						ReadRGB(&NewRGBT, &ColourInfo, Comp1, Comp2, Comp3, Comp4);
						if (!pNewColours->AddColour(&ColName, &NewRGBT, &ColourInfo))
							return FALSE;
					}
					break;

				case COLOURMODEL_CMYK:
					{
						ColourCMYK NewCMYK;
						ReadCMYK(&NewCMYK, &ColourInfo, Comp1, Comp2, Comp3, Comp4);
						if (!pNewColours->AddColour(&ColName, &NewCMYK, &ColourInfo))
							return FALSE;
					}
					break;

				case COLOURMODEL_HSVT:
					{
						ColourHSVT NewHSVT;
						ReadHSV(&NewHSVT, &ColourInfo, Comp1, Comp2, Comp3, Comp4);
						if (!pNewColours->AddColour(&ColName, &NewHSVT, &ColourInfo))
							return FALSE;
					}
					break;

				case COLOURMODEL_GREYT:
					{
						ColourGreyT NewGreyT;
						ReadGrey(&NewGreyT, &ColourInfo, Comp1);
						if (!pNewColours->AddColour(&ColName, &NewGreyT, &ColourInfo))
							return FALSE;
					}
					break;
				
					default:
						ERROR3("ColourListComponent::ImportColourDefinition unknown colour model!");
						break;
			}
			break;

		case EXPORT_COLOURTYPE_TINT:
			{
				// Set the correct colour type
				ColourInfo.Type = COLOURTYPE_TINT;

				// Read in the tint value from the colour definition record
				ReadTint(&ColourInfo, Comp1);

				// Now, try and add that to the system
				if (!pNewColours->AddTintOrShade(&ColName, &ColourInfo))
					return FALSE;
			}
			break;

		case EXPORT_COLOURTYPE_SHADE:
			{
				// Set the correct colour type
				ColourInfo.Type = COLOURTYPE_TINT;

				// Read in the shade value from the colour definition record
				ReadShade(&ColourInfo, Comp1, Comp2);

				// Now, try and add that to the system
				if (!pNewColours->AddTintOrShade(&ColName, &ColourInfo))
					return FALSE;
			}
			break;

		default:
			ERROR3("ColourListComponent::ImportColourDefinition unknown colourtype!");
			break;
	}

	return ok;
}

/********************************************************************************************

>	BOOL ColourListComponent::ReadRGB(ColourRGBT *pCol, NewColourInfo *pColourInfo,
									  UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	29/5/96
	Inputs:		pCol		- RGB colour data to fill in
				pColourInfo	- pointer to the colour info to fill in
				Comp1 .. 4	- colour components read in from the record 
	Outputs:	The data in the pCol and pColourInfo will have been filled in
	Returns:	True if value read ok, False otherwise.
	Purpose:	Read the RGB values from a Camelot RGB colour definition record.
	SeeAlso:	ColourListComponent::ImportColourDefinition;

********************************************************************************************/

BOOL ColourListComponent::ReadRGB(ColourRGBT *pCol, NewColourInfo *pColourInfo,
								  UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
{
	ERROR2IF(pCol == NULL,FALSE,"ColourListComponent::ReadRGB NULL pCol");
	ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadRGB NULL pColourInfo");

	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	// read the Red colour component in
	FIXED24 Value24 = 0.0;
	Value24.SetAsFixed24(Comp1);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[0] = TRUE;
	else
		pCol->Red = Value24;

	// read the Green colour component in
	Value24.SetAsFixed24(Comp2);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[1] = TRUE;
	else
		pCol->Green = Value24;

	// read the Blue colour component in
	Value24.SetAsFixed24(Comp3);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[2] = TRUE;
	else
		pCol->Blue = Value24;

	// No transparency
	pCol->Transparent = 0.0;

	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::ReadCMYK(ColourCMYK *pCol, NewColourInfo *pColourInfo,
									   UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	29/5/96
	Inputs:		pCol	- RGB colour data to fill in
				pColourInfo	- pointer to the colour info to fill in				
				Comp1 .. 4	- colour components read in from the record 
	Outputs:	The data in the pCol and pColourInfo will have been filled in
	Returns:	True if value read ok, False otherwise.
	Purpose:	Read the CMYK values from a Camelot CMYK colour definition record.
	SeeAlso:	ColourListComponent::ImportColourDefinition;

********************************************************************************************/

BOOL ColourListComponent::ReadCMYK(ColourCMYK *pCol, NewColourInfo *pColourInfo,
								   UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
{
	ERROR2IF(pCol == NULL,FALSE,"ColourListComponent::ReadCMYK NULL pCol");
	ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadCMYK NULL pColourInfo");

	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	// read the Cyan colour component in
	FIXED24 Value24 = 0.0;
	Value24.SetAsFixed24(Comp1);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[0] = TRUE;
	else
		pCol->Cyan = Value24;

	// read the Magenta colour component in
	Value24.SetAsFixed24(Comp2);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[1] = TRUE;
	else
		pCol->Magenta = Value24;

	// read the Yellow colour component in
	Value24.SetAsFixed24(Comp3);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[2] = TRUE;
	else
		pCol->Yellow = Value24;

	// read the Key colour component in
	Value24.SetAsFixed24(Comp4);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[3] = TRUE;
	else
		pCol->Key = Value24;

	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::ReadHSV(ColourHSVT *pCol, NewColourInfo *pColourInfo,
									  UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	29/5/96
	Inputs:		pCol	- HSVT colour data to fill in
				pColourInfo	- pointer to the colour info to fill in				
				Comp1 .. 4	- colour components read in from the record 
	Outputs:	The data in the pCol and pColourInfo will have been filled in
	Returns:	True if value read ok, False otherwise.
	Purpose:	Read the HSV values from a Camelot HSV colour definition record.
	SeeAlso:	ColourListComponent::ImportColourDefinition;

********************************************************************************************/

BOOL ColourListComponent::ReadHSV(ColourHSVT *pCol, NewColourInfo *pColourInfo,
								  UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
{
	ERROR2IF(pCol == NULL,FALSE,"ColourListComponent::ReadHSV NULL pCol");
	ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadHSV NULL pColourInfo");

	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	// read the Hue colour component in
	FIXED24 Value24 = 0.0;
	Value24.SetAsFixed24(Comp1);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[0] = TRUE;
	else
		pCol->Hue = Value24;

	// read the Saturation colour component in
	Value24.SetAsFixed24(Comp2);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[1] = TRUE;
	else
		pCol->Saturation = Value24;

	// read the Value colour component in
	Value24.SetAsFixed24(Comp3);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[2] = TRUE;
	else
		pCol->Value = Value24;
	
	// No transparency
	pCol->Transparent = 0.0;

	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::ReadGrey(ColourGreyT *pCol, NewColourInfo *pColourInfo, UINT32 Comp1)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	29/5/96
	Inputs:		pCol	- Grey colour data to fill in
				pColourInfo	- pointer to the colour info to fill in				
				Comp1	- the first of the colour components read in from the record 
	Outputs:	The data in the pCol and pColourInfo will have been filled in
	Returns:	True if value read ok, False otherwise.
	Purpose:	Read the Grey values from a Camelot Grey colour definition record.
	SeeAlso:	ColourListComponent::ImportColourDefinition;

********************************************************************************************/

BOOL ColourListComponent::ReadGrey(ColourGreyT *pCol, NewColourInfo *pColourInfo, UINT32 Comp1)
{
	ERROR2IF(pCol == NULL,FALSE,"ColourListComponent::ReadGrey NULL pCol");
	ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadGrey NULL pColourInfo");

	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	// read the grey Intensity colour component in
	FIXED24 Value24 = 0.0;
	Value24.SetAsFixed24(Comp1);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[0] = TRUE;
	else
		pCol->Intensity = Value24;

	// Clear the reserved words to 0.
	pCol->Reserved1 = 0.0;
	pCol->Reserved2 = 0.0;

	// No transparency
	pCol->Transparent = 0.0;

	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::ReadTint(NewColourInfo *pColourInfo, UINT32 Comp1)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	29/5/96
	Inputs:		pColourInfo	- pointer to the colour info to fill in				
				Comp1		- the first of the colour components read in from the record 
	Outputs:	The data in the pCol and pColourInfo will have been filled in
	Returns:	True if value read ok, False otherwise.
	Purpose:	Read the tint values from a Camelot tint colour definition record.
	SeeAlso:	ColourListComponent::ImportColourDefinition;

********************************************************************************************/

BOOL ColourListComponent::ReadTint(NewColourInfo *pColourInfo, UINT32 Comp1)
{
	ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadTint NULL pColourInfo");

	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	// read the grey Intensity colour component in
	FIXED24 Value24 = 0.0;
	Value24.SetAsFixed24(Comp1);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[0] = TRUE;

	pColourInfo->TintValue = Value24;

	pColourInfo->Type = COLOURTYPE_TINT;
	// And flag the fact that this "tint" is a tint rather than a shade!
	pColourInfo->TintIsShade = FALSE;

	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::ReadShade(NewColourInfo *pColourInfo, UINT32 Comp1, UINT32 Comp2)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	29/5/96
	Inputs:		pColourInfo	- pointer to the colour info to fill in				
				Comp1 .. 2	- the first two colour components read in from the record 
	Outputs:	The data in the pCol and pColourInfo will have been filled in
	Returns:	True if value read ok, False otherwise.
	Purpose:	Read the shade values from a Camelot shade colour definition record.
	SeeAlso:	ColourListComponent::ImportColourDefinition;

********************************************************************************************/

BOOL ColourListComponent::ReadShade(NewColourInfo *pColourInfo, UINT32 Comp1, UINT32 Comp2)
{
	ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadShade NULL pColourInfo");

	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	FIXED24 Value24 = 0.0;
	Value24.SetAsFixed24(Comp1);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[0] = TRUE;
	pColourInfo->TintValue = Value24;

	Value24.SetAsFixed24(Comp2);
	if (Linked && (Value24 == LinkValue))
		pColourInfo->Inherits[1] = TRUE;
	pColourInfo->ShadeValue = Value24;

	pColourInfo->Type = COLOURTYPE_TINT;
	// And flag the fact that this "tint" is a really a shade!
	pColourInfo->TintIsShade = TRUE;

	return TRUE;
}


/********************************************************************************************
********************************************************************************************/


/********************************************************************************************

>	BOOL ColourListComponent::StartExport(BaseCamelotFilter *pFilter)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/5/96
	Returns:	TRUE if the component was able to prepare for exporting;
				FALSE if not (e.g. out of memory)
	Inputs:		pFilter - the BaseCamelotFilter filter that is being used to export a file.
	Purpose:	Inform the colour list document component that a WEb or Native export is
				about to start.
	SeeAlso:	DocComponent

********************************************************************************************/

BOOL ColourListComponent::StartExport(BaseCamelotFilter *pFilter)
{
#ifdef DO_EXPORT
TRACEUSER( "Neville", _T("ColourListComponent::StartExport\n"));
	// Mark all colours as unsaved 
	if (pFilter == NULL)
	{
		ERROR3("ColourListComponent::StartExport filter is null!");
		return TRUE;
	}

	// Save this in our link to the BaseCamelotFilter
	pCamFilter = pFilter;

	// Set up and start the exported colour list
	pExportedColours = new ExportedColours();
	if (pExportedColours == NULL)
		return FALSE;
#endif
	return TRUE;
}

/********************************************************************************************

>	BOOL ColourListComponent::EndExport(BaseCamelotFilter *pFilter)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/5/96
	Inputs:		pFilter - the BaseCamelotFilter filter that is being used to import a file.
				Success - True if everything went swimmingly, False if just a clean up is required.
	Purpose:	Inform the colour list document component that a Web or Native export has
				just finished.
	Returns:	TRUE if the component was able to end the importing;
				FALSE if not (e.g. out of memory)
	SeeAlso:	DocComponent

********************************************************************************************/

BOOL ColourListComponent::EndExport(BaseCamelotFilter *pFilter, BOOL Success)
{
#ifdef DO_EXPORT
//	ERROR2IF(pExportedColours == NULL, FALSE, "ColourListComponent::EndExport no pExportedColours!");
	// If we error about the pExportedColours then we assume that the EndImport has been called.
	// This may not be the case if we are in clean up mode. So just handle it!

TRACEUSER( "Neville", _T("ColourListComponent::EndExport\n"));
	if (pFilter == NULL)
	{
		ERROR3("ColourListComponent::EndExport filter is null!");
		return TRUE;
	}

	// Check if we should be saving unused colours or not. Usually this is controlled by the
	// user in Web files and always done in Native files.
	// Do not do if we are just in clean up mode or have no pExportedColours (indicating in clean up mode)
	if (!pFilter->IsWebFilter() && !pFilter->GetRemoveUnusedColours() && Success && pExportedColours)
	{
TRACEUSER( "Neville", _T("ColourListComponent::EndExport exporting unsaved colours\n"));
		// Iterate over the document's list of named IndexedColours...
		IndexedColour *pCol = (IndexedColour *) pIndexedColours->GetHead();
		BOOL ok = TRUE;
		while (ok && pCol != NULL)
		{
			if (!pCol->IsDeleted())
			{
				// The colour is in use - save it to the file.
				ok = SaveColourAndParents(pCol, pFilter, 0);
			}

			// Try the next colour
			pCol = (IndexedColour *) pIndexedColours->GetNext(pCol);
		}

		// Iterate over the document's list of unnamed IndexedColours...
		List *pUnnamedColours = pIndexedColours->GetUnnamedColours();

		pCol = (IndexedColour *) pUnnamedColours->GetHead();

		ok = TRUE;
		while (ok && pCol != NULL)
		{
			if (!pCol->IsDeleted() && pCol->IsInUse())
			{
				// The colour is in use and is not deleted
				// - save it to the file.
				ok = SaveColourAndParents(pCol, pFilter, 0);
			}

			// Try the next colour
			pCol = (IndexedColour *) pUnnamedColours->GetNext(pCol);
		}
	}

#endif		
	return TRUE;
}



/********************************************************************************************

>	virtual void ColourListComponent::CleanUpAfterExport(BOOL Success)

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/8/96
	Inputs:		Success - True if everything went swimmingly, False if the export failed

	Purpose:	Inform the document component that a Web or Native export has just finished.

	Notes:		This is called after EndExport, so that the component can clean up any 
				during-export data structures. This allows situations like: PrintComponent
				wants to save a colour reference in it's EndExport call, but is called after
				the ColourComponent EndExport. The ColourComponent EndExport does not delete
				its data structures, so is still able to supply colour references to other
				components' EndExport functions.

	SeeAlso:	ColourListComponent::EndExport; DocComponent::CleanUpAfterExport

********************************************************************************************/

void ColourListComponent::CleanUpAfterExport(BOOL Success)
{
#ifdef DO_EXPORT
	// As we have finished with it now, destroy the list of exported colours
	if (pExportedColours)
	{
		delete pExportedColours;
		pExportedColours = NULL;
	}

	// Null our link to the BaseCamelotFilter
	pCamFilter = NULL;

#endif		
	return;
}



/********************************************************************************************

>	INT32 ColourListComponent::GetWriteColourReference(DocColour* pDocColour, BaseCamelotFilter *pFilter)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	24/5/96
	Inputs:		pDocCololour	- The document colour to save
				pFilter			- The filter to use for saving
	Outputs:	-
	Returns:	The colour reference for the doccolour ready for writing in a record.
				This will be zero if a problem has occurred. May return -1 if it does not
				need to save anything i.e if the colour is not in use and not named.

	Purpose:	Return the colour reference to the caller, who will then use it to write the
				colour in the record that they are preparing to save to a Web or Native file.
				In the process of getting the colour reference, the colour definition record
				for the colour reference will be generated and saved to the file. In Web format
				this will just be the simple colour record, in native files this will be the
				full colour definition, possibly preceeded by the parents for the colour, as
				these must be saved before the children as the children must have a valid
				colour reference.
				NOTE: As this does save information into the record stream, it *MUST* be called
				before the caller has called StartRecord() as otherwise the records will become
				intertwined!
	Errors:		-
	SeeAlso:	IndexedColour; SaveComplexColour; SaveSimpleColour; SaveColourAndParents;

********************************************************************************************/

INT32 ColourListComponent::GetWriteColourReference(DocColour* pDocColour, BaseCamelotFilter *pFilter)
{
#ifdef DO_EXPORT
	ERROR2IF(pDocColour == NULL,0L,"ColourListComponent::GetWriteColourReference null pDocColour");
	ERROR2IF(pFilter == NULL,0L,"ColourListComponent::GetWriteColourReference null pFilter");

	INT32 RecordNumber = 0L;
	
	// First, check to see if the doc colour is transparent. If so then just return the default
	// default reference for this
	if (pDocColour->IsTransparent())
		return REF_DEFAULTCOLOUR_TRANSPARENT;
	
	// Get the indexed colour which this DocColour refers to, if any.
	IndexedColour * pCol = pDocColour->FindParentIndexedColour();
	if (pCol)
	{
		// Its an indexed colour so either save it as a simple colour or a complex colour
		// depending on whether we are in Web or Native mode.
		if (pFilter->IsWebFilter())
		{
			// We are in Web mode so save the simple colour
			RecordNumber = SaveSimpleColour(pCol, pFilter);
		}
		else
		{
			// We are in Web mode so save the simple colour
			RecordNumber = SaveColourAndParents(pCol, pFilter);
		}
	}
	else
	{
		// its a simple colour, so save this out as a simple colour. 
		if (pFilter->IsWebFilter())
		{
			// its a simple colour, so just save this as a simple colour. 
			// We must add the RGB colours to our exported list, so that we only save the
			// definition out once. 
			RecordNumber = SaveSimpleColour(pDocColour, pFilter, TRUE);
		}
		else
		{
			// TODO:
			// Could change this later to save out a complex colour in native files so that
			// these are converted to indexed colours on loading. Jason reckons this is favourable.
			// If we save it as a simple colour then there are bound to be conversion errors as
			// we are going from 24 bit components down to 8 bits and then back.

			// Find a global colour context to convert this colour into RGB for us.
			ColourContextRGBT *cc = (ColourContextRGBT *)ColourManager::GetColourContext(COLOURMODEL_RGBT);
			ERROR3IF(cc == NULL, "ColourListComponent::GetWriteColourReference No global RGB colour context!? Something is very broken");
			if (cc == NULL)
				return 0L;
			
			// And convert the colour into a *packed* (8-bit components) colour structure
			PColourRGBT Result;
			cc->ConvertColour(pDocColour, (ColourPacked *)&Result);

			// Only write this record out if we have not done so already
			// Check by seeing if the colour is already in our exported colour list
			ExportColour* pExportCol = NULL;
			pExportCol = pExportedColours->GetColour(&Result);
			// If it is then do not save this colour
			if (pExportCol)
			{
				// Just return the record number as the colour reference to the caller
				RecordNumber = pExportCol->RecordNumber;
			}
			else
			{	
				// Create ourselves a new indexed colour to put our data in
				// Use the DocColour we have been supplied with, this should create an unnamed colour by default
				IndexedColour *pNewCol = new IndexedColour(*pDocColour);
				if (pNewCol)
				{
					// DY 3/5/2000 Now that I am now using the Reserved flag to indicate whether or not a doccolour
					// was created from a named colour and then de-indexed. For details see LineDefinition::ConvertIndexedColours
					// This means that if we get a doccolour with that flag set it was originally created by an indexed colour, so
					// we can call our function to find the parent
	
					
					IndexedColour* pIndexedCol = NULL;
					if (pDocColour->IsNamed())
					{
						// Diccon, this is a named colour that was originally generated from an indexed colour but
						// subsequently de-indexed for various reasons. Its original parent should be in the list
						// somewhere
						pIndexedCol = GetIndexedParentOfColour(*pDocColour);
					
					}
					else
						pNewCol->SetUnnamed();
		
					// Now save out the colour data in a complex colour record out to file
					// We cannot ask the routine to add this colour to the exported list as it is
					// not a REAL indexed colour in the indexed colour list, so say False.
					if (pIndexedCol == NULL)
						RecordNumber = SaveComplexColour(pNewCol, pFilter, FALSE);
					else
					// if we found an indexed colour then save out normally - DY
						RecordNumber = SaveColourAndParents(pIndexedCol, pFilter);	

					if (RecordNumber > 0)
					{
						// Add this colour to our list of exported items
						/*BOOL ok =*/ pExportedColours->AddColour(&Result, RecordNumber);
						// Should return this error to the caller but not fatal so just continue
					}

					// We have finished with our indexed colour and so remove it
					delete pNewCol;
				}
				else
				{
					// We failed to create the complex colour so we have no choice but to save
					// it as a simple colour. 
					// We must add the RGB colours to our exported list, so that we only save the
					// definition out once. 
					RecordNumber = SaveSimpleColour(pDocColour, pFilter, TRUE);
				}
			}
		}
	}
	
	return RecordNumber;
#endif
	return 0L;
}

/********************************************************************************************

>	INT32 ColourListComponent::SaveSimpleColour(IndexedColour *pCol, BaseCamelotFilter *pFilter)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/5/96
	Inputs:		pCol		- The (root) colour to save
				pFilter		- The filter to use for saving
	Outputs:	-
	Returns:	The record number for this colour, if it has been saved correctly or zero
				if a problem has occurred. May return -1 if it does not need to save anything
				i.e if the colour is not in use and not named.
	Purpose:	Save out an indexed colour to a Web or Native file. Returns a record number or
				colour reference to the caller ready for use by somebody else to save in their
				record.
				This is the Web file form of saving colours.
	Errors:		-
	SeeAlso:	-

********************************************************************************************/

INT32 ColourListComponent::SaveSimpleColour(IndexedColour *pCol, BaseCamelotFilter *pFilter)
{
#ifdef DO_EXPORT
	ERROR2IF(pCol == NULL || pFilter == NULL, 0L, "ColourListComponent::SaveSimpleColour no pCol or pFilter supplied!");
	ERROR2IF(pExportedColours == NULL, 0L, "ColourListComponent::SaveSimpleColour no pExportedColours!");
	
	// Use same condition as SaveColourAndChildren so that if the colour is unnamed
	// and it's not actually used anywhere, don't bother saving it.
	// This optimises out temporary locals that are no longer needed. At the worst,
	// if something goes horribly wrong, this just means that some locals might turn up
	// as CMYK definitions on reloading, but this shouldn't cause any problems unless
	// something deeply scary has happened to the colour system.
	if (!pCol->IsNamed() && !pCol->IsInUse())
		return -1L;

	// Only write this record out if we have not done so already
	// Check by seeing if the colour is already in our exported colour list
	ExportColour* pExportCol = NULL;
	pExportCol = pExportedColours->GetColour(pCol);
	// If it is then do not save this colour
	if (pExportCol)
	{
		// Just return the record number as the colour reference to the caller
		return pExportCol->RecordNumber;
	}	

	// Create a DocColour referencing this IndexedColour.
	DocColour SimpleColour;
	SimpleColour.MakeRefToIndexedColour(pCol);

	// Save this as a document colour, don't check the export colour list as we are an indexed colour
	// really and so have cope with the list ourselves.
	INT32 RecordNumber = SaveSimpleColour(&SimpleColour, pFilter, FALSE);
	// returns 0 if there was a problem, exit now
	if (RecordNumber == 0)
		return RecordNumber;

	// Add this colour to our list of exported items
	BOOL ok = pExportedColours->AddColour(pCol, RecordNumber);
	// If we have had a problem at any of the stages then return that to the caller
	if (!ok)
		return 0L;

	// Everything went tickety boo, so return the record number to the caller.
	return RecordNumber;
#else
	return 0L;
#endif
}

/********************************************************************************************

>	INT32 ColourListComponent::SaveSimpleColour(DocColour *pDocCol, BaseCamelotFilter *pFilter,
											   BOOL CheckSimpleColourList = FALSE)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/5/96
	Inputs:		pDocCol		- The document colour to save
				pFilter		- The filter to use for saving
				CheckSimpleColourList - If TRUE then check the export colour list to see if we
										have saved this simple colour before
										If FALSE then this is an indexed colour so don't search
										the export colour list
	Outputs:	-
	Returns:	The record number for this colour, if it has been saved correctly or zero
				if a problem has occurred. May return -1 if it does not need to save anything
				i.e if the colour is not in use and not named.
	Purpose:	Save out a document colour to a Web or Native file. Returns a record number or
				colour reference to the caller ready for use by somebody else to save in their
				record.
				This is the Web file form of saving colours.
	Errors:		-
	SeeAlso:	-

********************************************************************************************/

INT32 ColourListComponent::SaveSimpleColour(DocColour *pDocCol, BaseCamelotFilter *pFilter,
										   BOOL CheckSimpleColourList)
{
#ifdef DO_EXPORT
	ERROR2IF(pDocCol == NULL || pFilter == NULL, 0L, "ColourListComponent::SaveSimpleColour no pCol or pFilter supplied!");

	// Find a global colour context to convert this colour into RGB for us.
	ColourContextRGBT *cc = (ColourContextRGBT *)ColourManager::GetColourContext(COLOURMODEL_RGBT);
	ERROR3IF(cc == NULL, "ColourListComponent::SaveSimpleColour No global RGB colour context!? Something is very broken");
	if (cc == NULL)
		return 0L;
	
	// And convert the colour into a *packed* (8-bit components) colour structure
	PColourRGBT Result;
	cc->ConvertColour(pDocCol, (ColourPacked *)&Result);

	// If this is a simple colour rather than a simple colour of an indexed colour then
	// check to see if we have saved it already. If so then just return the record number
	if (CheckSimpleColourList)
	{
		// Only write this record out if we have not done so already
		// Check by seeing if the colour is already in our exported colour list
		ExportColour* pExportCol = NULL;
		pExportCol = pExportedColours->GetColour(&Result);
		// If it is then do not save this colour
		if (pExportCol)
		{
			// Just return the record number as the colour reference to the caller
			return pExportCol->RecordNumber;
		}	
	}

	// And finally, read the bytes out of the packed colour struct.
	BYTE RedByteValue = Result.Red;
	BYTE GreenByteValue = Result.Green;
	BYTE BlueByteValue = Result.Blue;

	INT32 RecordNumber = 0L;
	if (RedByteValue == 0xFF && GreenByteValue == 0xFF && BlueByteValue == 0xFF)
	{
		RecordNumber = REF_DEFAULTCOLOUR_WHITE;
	}
	else if (RedByteValue == 0x00 && GreenByteValue == 0x00 && BlueByteValue == 0x00)
	{
		RecordNumber = REF_DEFAULTCOLOUR_BLACK;
	}
	else if (RedByteValue == 0xFF && GreenByteValue == 0x00 && BlueByteValue == 0x00)
	{
		RecordNumber = REF_DEFAULTCOLOUR_RED;
	}
	else if (RedByteValue == 0x00 && GreenByteValue == 0xFF && BlueByteValue == 0x00)
	{
		RecordNumber = REF_DEFAULTCOLOUR_GREEN;
	}
	else if (RedByteValue == 0x00 && GreenByteValue == 0x00 && BlueByteValue == 0xFF)
	{
		RecordNumber = REF_DEFAULTCOLOUR_BLUE;
	}
	else if (RedByteValue == 0x00 && GreenByteValue == 0xFF && BlueByteValue == 0xFF)
	{
		RecordNumber = REF_DEFAULTCOLOUR_CYAN;
	}
	else if (RedByteValue == 0xFF && GreenByteValue == 0x00 && BlueByteValue == 0xFF)
	{
		RecordNumber = REF_DEFAULTCOLOUR_MAGENTA;
	}
	else if (RedByteValue == 0xFF && GreenByteValue == 0xFF && BlueByteValue == 0x00)
	{
		RecordNumber = REF_DEFAULTCOLOUR_YELLOW;
	}
	else
	{
		BOOL ok = TRUE;
		// Write the data out to the file
		//INT32 RecordNumber = pFilter->StartRecord(TAG_DEFINERGBCOLOUR, TAG_DEFINERGBCOLOUR_SIZE);
		CXaraFileRecord Rec(TAG_DEFINERGBCOLOUR,TAG_DEFINERGBCOLOUR_SIZE);
		ok = Rec.Init();

		if (ok) ok = Rec.WriteBYTE(RedByteValue);
		if (ok) ok = Rec.WriteBYTE(GreenByteValue);
		if (ok) ok = Rec.WriteBYTE(BlueByteValue);

		// Finally, write the record out to file
		// In the process get the record number that this was written out as
		if (ok) RecordNumber = pFilter->WriteDefinitionRecord(&Rec);
		
		// If we have had a problem at any of the stages then return that to the caller
		if (!ok || RecordNumber <= 0)
			return 0L;
	}

	// If this is a simple colour rather than a simple colour of an indexed colour then
	// add it to the list so that we do not save out the definition twice!
	if (CheckSimpleColourList)
	{
		// Add this colour to our list of exported items
		BOOL ok = pExportedColours->AddColour(&Result, RecordNumber);
		// If we have had a problem at any of the stages then return that to the caller
		if (!ok)
			return 0L;
	}

	// Everything went tickety boo, so return the record number to the caller.
	return RecordNumber;
#else
	return 0L;
#endif
}

// Simple macro to make the code in SaveColourAndParents() a bit neater.
#define LINKED_COLOUR(ID) (Linked && pCol->InheritsComponent((ID)))

/********************************************************************************************

>	INT32 ColourListComponent::SaveColourAndParents(IndexedColour *pCol, BaseCamelotFilter *pFilter,
													INT32 NestingLevel = 0)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/5/96
	Inputs:		pCol			- The (root) colour to save
				pFilter			- The filter to use for saving
				NestingLevel	- How many parental levels up we have gone so far
	Outputs:	-
	Returns:	The record number for this colour, if it has been saved correctly or zero
				if a problem has occurred. May return -1 if it does not need to save anything
				i.e if the colour is not in use and not named.
	Purpose:	Save out an indexed colour to a Web or Native file. Returns a record number or
				colour reference to the caller ready for use by somebody else to save in their
				record.
				This is the Web file form of saving colours.
	Purpose:	Save out an indexed colour in its complex form usually to a Native file.
				If it has any parents then these must be saved out before it, as the colour
				reference for the parent *MUST* be a real record number which has been 
				previously saved into the stream.
				Returns a record number or colour reference to the caller ready for use by
				somebody else to save in their record.
				This is the Native file form of saving colours.
	Errors:		-
	SeeAlso:	-

********************************************************************************************/

INT32 ColourListComponent::SaveColourAndParents(IndexedColour *pCol, BaseCamelotFilter *pFilter,
												INT32 NestingLevel)
{
#ifdef DO_EXPORT
	ERROR2IF(pCol == NULL || pFilter == NULL, 0L, "ColourListComponent::SaveColourAndParents no pCol or pFilter!");
	ERROR2IF(pExportedColours == NULL, 0L, "ColourListComponent::SaveColourAndParents no pExportedColours!");
	
	// Use same condition as SaveColourAndChildren so that if the colour is unnamed
	// and it's not actually used anywhere, don't bother saving it.
	// This optimises out temporary locals that are no longer needed. At the worst,
	// if something goes horribly wrong, this just means that some locals might turn up
	// as CMYK definitions on reloading, but this shouldn't cause any problems unless
	// something deeply scary has happened to the colour system.
	if (!pCol->IsNamed() && !pCol->IsInUse())
		return -1L;

	// Check for silly recursion errors	[not that you can get circular references with
	// the amazingly strict and careful checking done by the IndexedColour class.
	// Same test as SaveColourAndChildren.
	ERROR2IF(NestingLevel > 200, 0L, "ColourListComponent::SaveColourAndParents - Rampant linked colour nesting detected!");

	// ****
	// **** First, save parents of this colour, if any and if not saved previously
	// ****

	// Before we save out this colour, we must check if it has a parent, if so then
	// we must save out the parents first as we must reference parents by a record
	// number and hence it must have already been saved!

	// So, recurse and save out any parents of this colour (links or tints)...

	// Get all the named colours that are immediate children of this colour
	// This only returns a parent if this is a colour with a valid parent e.g. tint
	IndexedColour *pParent = pCol->FindLinkedParent();
	//IndexedColour *pParentCol = pParent;
	ExportColour* pExportCol = NULL;
	while (pParent != NULL)
	{
		if (!pParent->IsDeleted())
		{
			// Found a parent - save out via recursion so we save all its ascendants in the
			// right order...
			// To save time, check here if this parent is already in our list, if it this
			// then no point in recursing through the chain of parents as they all have already
			// been saved.
			pExportCol = pExportedColours->GetColour(pParent);
			// If it is NULL then we have not already saved this colour, so do so.
			if (pExportCol == NULL)
				SaveColourAndParents(pParent, pFilter, NestingLevel + 1);
		}

		// Try the next colour
		pParent = pParent->FindLinkedParent();
	}

	// ****
	// **** Saved this colour before?
	// ****

	// Only write this record out if we have not done so already
	// Check by seeing if the colour is already in our exported colour list
	pExportCol = pExportedColours->GetColour(pCol);
	// If it is then do not save this colour
	if (pExportCol)
	{
		// Just return the record number as the colour reference to the caller
		return pExportCol->RecordNumber;
	}	

	// Now save out the colour data in a complex colour record out to file
	// We want this indexed colour adding to the exported list and so say TRUE
	INT32 RecordNumber = SaveComplexColour(pCol, pFilter, TRUE);

	// Everything went tickety boo, so return the record number to the caller.
	return RecordNumber;
#else
	return 0L;
#endif
}

/********************************************************************************************

>	INT32 ColourListComponent::SaveComplexColour(IndexedColour *pCol, BaseCamelotFilter *pFilter,
												BOOL AddColourToList = TRUE)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	4/6/96
	Inputs:		pCol			- The (root) colour to save
				pFilter			- The filter to use for saving
				AddColourToList	- True if we are to add this colour to the exported colour list
								- False if the caller has already done this
	Outputs:	-
	Returns:	The record number for this colour, if it has been saved correctly or zero
				if a problem has occurred. May return -1 if it does not need to save anything
				i.e if the colour is not in use and not named.
	Purpose:	Actually save out an indexed colour to a Web or Native file in a complex colour
				record. Returns a record number or colour reference to the caller ready for use
				by somebody else to save in their record.
				If it has any parents then these must be saved out before it, as the colour
				reference for the parent *MUST* be a real record number which has been 
				previously saved into the stream.
				Returns a record number or colour reference to the caller ready for use by
				somebody else to save in their record.
				This is the Native file form of saving colours.
	Errors:		-
	SeeAlso:	SaveColourAndParents; GetWriteColourReference;

********************************************************************************************/
INT32 ColourListComponent::SaveComplexColour(IndexedColour *pCol, BaseCamelotFilter *pFilter,
											BOOL AddColourToList)
{
#ifdef DO_EXPORT

	ERROR2IF(pCol == NULL || pFilter == NULL, 0L, "ColourListComponent::SaveComplexColour no pCol or pFilter!");
	ERROR2IF(pExportedColours == NULL, 0L, "ColourListComponent::SaveComplexColour no pExportedColours!");

	// When GetColourLinePosition is TRUE, it means that we want to save the colour's pos on the colour
	// line, so that it can be imported in the correct order.
	//
	// This is set to AddColourToList by default - i.e. assume that if it's being added to the list of exported
	// colours, then we probably want to preserve the colour' pos
	BOOL GetColourLinePosition = AddColourToList;

	// ****
	// **** Get the information on the colour
	// ****

	// Get information on the colour - ask for its full identifier rather than just the name,
	// so we get a unique id for unnamed colours rather than just "Local colour"
	ColourModel Model = pCol->GetColourModel();
	ColourGeneric GenCol;
	IndexedColourType ColType = pCol->GetType();
	pCol->GetSourceColour(&GenCol);
	String_64 ColName = *(pCol->GetName(TRUE));
	if (ColName[0] == '_')
	{
		// We have an unnamed colour and so the name should be blank
		ColName.Empty();

		// If it's an unnamed colour, then it's assumed it's not on the colour line, so we
		// won't need to find it's pos on the colour line
		GetColourLinePosition = FALSE;
	}

	//TCHAR *ColName = (TCHAR *) (*(pCol->GetName(TRUE)));

	// Find a global colour context to convert this colour into RGB for us.
	ColourContextRGBT *cc = (ColourContextRGBT *)ColourManager::GetColourContext(COLOURMODEL_RGBT);
	ERROR3IF(cc == NULL, "ColourListComponent::SaveComplexColour No global RGB colour context!? Something is very broken");
	if (cc == NULL)
		return 0L;

	BOOL ok = FALSE;
	// Create a DocColour referencing this IndexedColour.
	DocColour SimpleColour;
	SimpleColour.MakeRefToIndexedColour(pCol);

	// And convert the colour into a *packed* (8-bit components) colour structure
	PColourRGBT Result;
	cc->ConvertColour(&SimpleColour, (ColourPacked *)&Result);

	// And finally, read the bytes out of the packed colour struct.
	BYTE RedByteValue = Result.Red;
	BYTE GreenByteValue = Result.Green;
	BYTE BlueByteValue = Result.Blue;

	// ****
	// **** Save the record
	// ****

	// Write the data out to the file
	UINT32 Size = TAG_DEFINECOMPLEXCOLOUR_SIZE;
	// If there is a string name, then add it to this size
	// REMEMBER: We save out unicode strings and so we need to double the length of the returned string length
	Size += (ColName.Length() + 1) * SIZEOF_XAR_UTF16;

//	INT32 RecordNumber = pFilter->StartRecord(TAG_DEFINECOMPLEXCOLOUR, Size);
	CXaraFileRecord Rec(TAG_DEFINECOMPLEXCOLOUR, Size);
	ok = Rec.Init();

	// Start with the simple RGB colour
	if (ok) ok = Rec.WriteBYTE(RedByteValue);
	if (ok) ok = Rec.WriteBYTE(GreenByteValue);
	if (ok) ok = Rec.WriteBYTE(BlueByteValue);

	// Now write out the colour model...
	if (ok) ok = Rec.WriteBYTE((BYTE)Model);

	// Now write out the colour type...
	// Include flags about linking in colour type?
	// If the colour is linked, we save out the component as an illegal known value
	// Convert the colour types into export colour types
	// Should be a straight conversion but just in case...
	ExportColourType ExpColType=EXPORT_COLOURTYPE_NORMAL;
	switch (ColType)
	{
		case COLOURTYPE_NORMAL:	ExpColType = EXPORT_COLOURTYPE_NORMAL;	break;
		case COLOURTYPE_SPOT:	ExpColType = EXPORT_COLOURTYPE_SPOT;	break;
		case COLOURTYPE_LINKED:	ExpColType = EXPORT_COLOURTYPE_LINKED;	break;
		case COLOURTYPE_TINT:
			if (pCol->TintIsShade())
				ExpColType = EXPORT_COLOURTYPE_SHADE;
			else
				ExpColType = EXPORT_COLOURTYPE_TINT;
			break;
		default:
			ERROR3("ColourListComponent::SaveColour - Unknown colour model!");
			break;
	}
	if (ok) ok = Rec.WriteBYTE((BYTE)ExpColType);

	// Write out the entry number this colour is in the indexed colour list
	UINT32 ColourListNumber = 0L;
	// If GetColourLinePosition is False then the indexed colour is not on the colour line.
	// so do NOT try and go through the list of colours to find its pos number, just use zero.
	if (GetColourLinePosition)
		ColourListNumber = GetIndexColourNumber(pCol); 
	if (ok) ok = Rec.WriteUINT32(ColourListNumber);

	// Write out the reference number of the parent colour
	UINT32 ParentColourRef = 0L; 
	IndexedColour *pParentCol = pCol->FindLinkedParent();
	ExportColour* pExportCol = NULL;
	if (pParentCol)
	{
		// If there is a parent then recover the record number from the exported colours list 
		pExportCol = pExportedColours->GetColour(pParentCol);
		ERROR2IF(pExportCol == NULL,FALSE,"ColourListComponent::SaveComplexColour Not exported parent before child!");
		ParentColourRef = pExportCol->RecordNumber;
		TRACEUSER( "Neville", _T("Saving parent reference %d\n"),ParentColourRef);
	}

	if (ok) ok = Rec.WriteReference(ParentColourRef);

	BOOL Linked = (ColType == COLOURTYPE_LINKED);
	switch (ColType)
	{
		
		case COLOURTYPE_NORMAL:
		case COLOURTYPE_SPOT:
		case COLOURTYPE_LINKED:
		{
			// These all require the same handling
			// Linked colours save out the components in the normal fashion

			// Now write out the colour component values depending on the model in use...
			switch (Model)
			{
				case COLOURMODEL_RGBT:
					// Now add the RGB components.
					// Stored as FIXED24s.
					ColourRGBT *pRGBT;
					pRGBT = (ColourRGBT *) &GenCol;
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pRGBT->Red, LINKED_COLOUR(1)));
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pRGBT->Green,	LINKED_COLOUR(2)));
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pRGBT->Blue, LINKED_COLOUR(3)));
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pRGBT->Transparent, LINKED_COLOUR(4)));
					break;

				case COLOURMODEL_HSVT:
					// Now add the HSV components.
					ColourHSVT *pHSVT;
					pHSVT = (ColourHSVT *) &GenCol;
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pHSVT->Hue, LINKED_COLOUR(1)));
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pHSVT->Saturation, LINKED_COLOUR(2)));
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pHSVT->Value, LINKED_COLOUR(3)));
					if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
					break;

				case COLOURMODEL_CMYK:
					// Now add the CMYK components.
					ColourCMYK *pCMYK;
					pCMYK = (ColourCMYK *) &GenCol;
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pCMYK->Cyan, LINKED_COLOUR(1)));
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pCMYK->Magenta, LINKED_COLOUR(2)));
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pCMYK->Yellow, LINKED_COLOUR(3)));
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pCMYK->Key, LINKED_COLOUR(4)));
					break;

				case COLOURMODEL_GREYT:
					// greyscale colour.
					ColourGreyT *pGreyT;
					pGreyT = (ColourGreyT *) &GenCol;
					if (ok) ok = Rec.WriteUINT32(AddComponentValue(pGreyT->Intensity, LINKED_COLOUR(1)));
					if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
					if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
					if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
					break;

				default:
					ERROR3("ColourListComponent::SaveColour - Unknown colour model!");
					break;
			}
			break;
		}

		case COLOURTYPE_TINT:
		{
			// If we have a tint colour then this needs special handling
			FIXED24 TintVal(0.0);
			FIXED24 ShadeVal(0.0);
			// Is the tint a tint or is it really a shade
			// Add tint identifier to colour definition
			if (pCol->TintIsShade())
			{
				ShadeVal = pCol->GetShadeValueX();
				TintVal  = pCol->GetShadeValueY();
				if (ok) ok = Rec.WriteUINT32(AddComponentValue(ShadeVal, LINKED_COLOUR(1)));
				if (ok) ok = Rec.WriteUINT32(AddComponentValue(TintVal, LINKED_COLOUR(1)));
				if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
				if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
			}
			else
			{
				TintVal  = pCol->GetTintValue();
				if (ok) ok = Rec.WriteUINT32(AddComponentValue(TintVal, LINKED_COLOUR(1)));
				if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
				if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
				if (ok) ok = Rec.WriteUINT32(0);	// pad to 4 colour components
			}
			break;
		}
		default:
			ERROR3("ColourListComponent::SaveColour - Unknown colour type!");
			break;
	}

	// Write out the name of the colour
	if (ok) ok = Rec.WriteUnicode(ColName);

	// Finally, write the record out to file
	INT32 RecordNumber = 0L;
	if (ok) RecordNumber = pFilter->WriteDefinitionRecord(&Rec);

	// Has the caller handled adding this to the colour list already? No, so do it oursleves.
	if (AddColourToList && RecordNumber > 0)
	{
		// Add this colour to our list of exported items
		ok = pExportedColours->AddColour(pCol, RecordNumber);
	}
//TRACEUSER( "Neville", _T("Saving colour %s, number %d, entry number %d\n"),(TCHAR*)ColName, RecordNumber, ColourListNumber);

	// If we have had a problem at any of the stages then return that to the caller
	if (!ok)
		return 0L;

	// Everything went tickety boo, so return the record number to the caller.
	return RecordNumber;
#else
	return 0L;
#endif
}

/********************************************************************************************

>	UINT32 ColourListComponent::AddComponentValue(FIXED24 ComponentValue, BOOL Inherited)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	28/5/96
	Inputs:		ComponentValue - the value to be returned.
				Inherited - TRUE => This component is inherited, so just output a known illegal value
						   FALSE => This component is not inherited, so output the
									actual value to the string
	Outputs:	-
	Returns:	The colour component as a UINT32 ready to write out to file.
	Purpose:	Returns either the colour component value or if it is inherited, a known illegal
				value which we can intepret on import to be an overridden value. 
				Doing it in a function centralises the syntax of inherited components.
	Errors:		-
	SeeAlso:	ColourListComponent::SaveColourAndParents

********************************************************************************************/

UINT32 ColourListComponent::AddComponentValue(FIXED24 ComponentValue, BOOL Inherited)
{
	// Construct the colour component value
	UINT32 ColourValue = 0L;

	// If this is a linked colour, and this component is inherited, then just add a '-'.
	if (Inherited)
	{
		ColourValue = FIXED24(-8.0).GetAsFixed24();
	}
	else
	{
		// We have to output the component....
		ColourValue = ComponentValue.GetAsFixed24();
	}

	return ColourValue;
}

/********************************************************************************************

>	INT32 ColourListComponent::GetIndexColourNumber(IndexedColour *pCol)

	Author:		Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
	Created:	21/5/96
	Inputs:		pCol - the indexed colour to search out the number for.
	Returns:	The number of this indexed colour in the list of colours (i.e.position)
	Purpose:	Work out the index of this colour in the list of indexed colours so that we
				can try and load back the colours in the same order.
				Unfortunately, the only way it seems that we can work out this number is by
				counting back to the start of the indexed colour list. Doh!
	SeeAlso:	IndexedColour

********************************************************************************************/

INT32 ColourListComponent::GetIndexColourNumber(IndexedColour *pCol)
{
	ERROR2IF(pCol==NULL,0,"ColourListComponent::GetIndexColourNumber no Colour pointer");
	ERROR2IF(pIndexedColours==NULL,0,"ColourListComponent::GetIndexColourNumber no pIndexedColours");

	INT32 number = 0;

	// Due to pants list class, we need to check that there is a previous memember before we
	// call GetPrev, otherwise it ensures all over the place. Why it can't just return NULL!
	if (pIndexedColours->IsEmpty())
		return number;

	// Go from this item to the start of the inddexed colour list, counting items as we go
	while (pCol)
	{
		pCol = (IndexedColour *) pIndexedColours->GetPrev(pCol);
		// If the colour is not deleted then count it
		if (pCol && !pCol->IsDeleted())
			number ++;
	}

	return number;
}


/********************************************************************************************
********************************************************************************************/

// Remove the preceeding code on all builds but those who want it

/********************************************************************************************
********************************************************************************************/

/********************************************************************************************

>	BOOL ColourListComponent::EPSStartImport(EPSFilter *pFilter)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	03/08/94
	Inputs:		pFilter - the EPS filter that is being used to import a file.
	Purpose:	Inform the colour list document component that an EPS import is about to 
				start.
	SeeAlso:	DocComponent

********************************************************************************************/

BOOL ColourListComponent::EPSStartImport(EPSFilter *pFilter)
{
	// Is this a Camelot EPS filter?
	BOOL CamelotEPS = pFilter->IS_KIND_OF(CamelotEPSFilter);

	// Get a colour table (and don't do strict checking if we are loading Camelot EPS).
	pNewColours = new ImportedColours(this, !CamelotEPS);
	if ((pNewColours == NULL) || !pNewColours->Init())
		return FALSE;

	// We keep a record of how nested we are with respect to linking colours, e.g.
	// links of links of links.
	// A nesting of 0 is no nesting.
	LinkNesting = 0;

	// Must have worked
	return TRUE;
}

/********************************************************************************************

>	void ColourListComponent::EPSEndImport(EPSFilter *pFilter, BOOL Success)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	03/08/94
	Inputs:		pFilter - the EPS filter that is being used to import a file.
				Success - TRUE => The import was successful;
						 FALSE => The import failed - abandon any changes.
	Purpose:	Inform the colour list document component that an EPS import has just 
				finished.
	SeeAlso:	DocComponent

********************************************************************************************/

void ColourListComponent::EPSEndImport(EPSFilter *pFilter, BOOL Success)
{
	ERROR3IF(pNewColours == NULL, "No colour table in EndEPSImport");

	// If we didn't even get to initialise, then return quietly.
	if (pNewColours == NULL)
		return;

	// Import is finished, so add any outstanding colours to the document (if the
	// import was successful), and delete the colour table
	if (Success)
	{
		pNewColours->AddColoursToDocument();
	}
	else
	{
		// Import failed - destroy all the colours.
		pNewColours->DestroyColours();
	}

	// Finally, delete the IndexedColour table.
	delete pNewColours;
	pNewColours = NULL;
}



/********************************************************************************************

>	void ColourListComponent::AddNewColour(IndexedColour *pNewCol)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	08/08/94
	Inputs:		pNewCol - the colour to add.
	Purpose:	Adds an indexed colour to the colour list (which in turn ensures that
				it has a unique colour name)
	SeeAlso:	ColourList::AddItem

********************************************************************************************/

void ColourListComponent::AddNewColour(IndexedColour *pNewCol)
{
	ERROR3IF(pNewCol == NULL,
				"ColourListComponent::AddNewColour: The colour to add is NULL!");
	ERROR3IF(pIndexedColours == NULL,
				"ColourListComponent::AddNewColour: I have no IndexedColour list!");

	// Add the colour, ensuring that it has a unique name
	pIndexedColours->AddItem(pNewCol);
}



/********************************************************************************************

>	BOOL ColourListComponent::WriteEPSComments(EPSFilter *pFilter)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	02/08/94
	Inputs:		pFilter - the filter being used to import the EPS file.
	Returns:	TRUE if the colour table was written successfully;
				FALSE if not.
	Purpose:	Writes out the colour table in the form of EPS comments in the 'header'
				comments of the EPS file.

	Notes:		IMPORTANT: Version 1.1 file extensions (Jason, 7/9/95 & 14/10/95)
				For this version, Shade colours have been added. 
				To retain backward compatability,
				all shades and their children are written into a second colour table
				(a %%JWColourTable). This means old loader code will skip them and use
				the inlined CMYK definitions, thus retaining the appearance of the document
				while only losing unsupported colour linking info.
				Thus, we do a 2-pass scheme. The first pass will (by use of default params
				in SaveColourAndChildren) fail to save out any shades and children.
				The second pass then saves all shades and their parents and children.
				Note this means parent colours can be saved twice, but these will be
				happily merged on loading, so no bad effects occur.

				Shades are only saved out in CamelotEPS. In Artworks EPS mode, they
				become standalone named colours.

	Errors:		Out of disk space, and similar disk errors.
	SeeAlso:	DocComponent::WriteEPSComments;
				DocComponent

********************************************************************************************/

BOOL ColourListComponent::WriteEPSComments(EPSFilter *pFilter)
{
#ifdef DO_EXPORT
	if (pFilter->IsKindOf(CC_RUNTIME_CLASS(ArtWorksEPSFilter)))
	{
		// Is it a Camelot specific filter?
		BOOL CamelotEPS = pFilter->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSFilter));

		// Output the colour table in ArtWorks format.
		EPSExportDC *pDC = pFilter->GetExportDC();

		// The ArtWorks EPS comment:
		pDC->OutputToken(_T("%%AWColourTable"));
		pDC->OutputNewLine();

		// Iterate over the document's list of named IndexedColours...
		IndexedColour *pCol = (IndexedColour *) pIndexedColours->GetHead();

		while (pCol != NULL)
		{
			if (!pCol->IsDeleted() && 
				((pCol->GetType() == COLOURTYPE_NORMAL) || 
				 (pCol->GetType() == COLOURTYPE_SPOT)))
			{
				// The colour is in use and is not a linked colour or tint - save it to 
				// the EPS file.
				SaveColourAndChildren(pCol, pDC, CamelotEPS);

			}

			// Try the next colour
			pCol = (IndexedColour *) pIndexedColours->GetNext(pCol);
		}

		// Iterate over the document's list of unnamed IndexedColours...
		List *pUnnamedColours = pIndexedColours->GetUnnamedColours();

		pCol = (IndexedColour *) pUnnamedColours->GetHead();

		while (pCol != NULL)
		{
			if (!pCol->IsDeleted() && pCol->IsInUse() &&
				((pCol->GetType() == COLOURTYPE_NORMAL) || 
				 (pCol->GetType() == COLOURTYPE_SPOT)))
			{
				// The colour is in use and is not a linked colour or tint - save it to 
				// the EPS file.
				SaveColourAndChildren(pCol, pDC, CamelotEPS);
			}

			// Try the next colour
			pCol = (IndexedColour *) pUnnamedColours->GetNext(pCol);
		}


		// --- PASS 2 - version 1.1 second colour table for shades and other extensions
		if (CamelotEPS)
		{
			// This variable is used to stop us outputting the colour table section
			// if it is not needed - we only output the header line when we write the
			// first colour out to this table.
			BOOL HaveOutputHeader = FALSE;

			// Iterate over the document's list of named IndexedColours...
			IndexedColour *pCol = (IndexedColour *) pIndexedColours->GetHead();

			while (pCol != NULL)
			{
				if (!pCol->IsDeleted() && 
					((pCol->GetType() == COLOURTYPE_NORMAL) || 
					 (pCol->GetType() == COLOURTYPE_SPOT)))
				{
					// The colour is in use and is not a linked colour or tint - save it to 
					// the EPS file.
					if (ColourOrChildIsShade(pCol))
					{
						if (!HaveOutputHeader)
						{
							// Output the header comment if we haven't already done so
							pDC->OutputToken(_T("%%JWColourTable"));
							pDC->OutputNewLine();
							HaveOutputHeader = TRUE;
						}

						SaveColourAndChildren(pCol, pDC, CamelotEPS, 0, TRUE);
					}
				}

				// Try the next colour
				pCol = (IndexedColour *) pIndexedColours->GetNext(pCol);
			}

			// Iterate over the document's list of unnamed IndexedColours...
			List *pUnnamedColours = pIndexedColours->GetUnnamedColours();

			pCol = (IndexedColour *) pUnnamedColours->GetHead();

			while (pCol != NULL)
			{
				if (!pCol->IsDeleted() && pCol->IsInUse() &&
					((pCol->GetType() == COLOURTYPE_NORMAL) || 
					 (pCol->GetType() == COLOURTYPE_SPOT)))
				{
					// The colour is in use and is not a linked colour or tint - save it to 
					// the EPS file.
					if (ColourOrChildIsShade(pCol))
					{
						if (!HaveOutputHeader)
						{
							// Output the header comment if we haven't already done so
							pDC->OutputToken(_T("%%JWColourTable"));
							pDC->OutputNewLine();
							HaveOutputHeader = TRUE;
						}

						SaveColourAndChildren(pCol, pDC, CamelotEPS, 0, TRUE);
					}
				}

				// Try the next colour
				pCol = (IndexedColour *) pUnnamedColours->GetNext(pCol);
			}
			
		}
	}
#endif
	// All ok.
	return TRUE;
}

/********************************************************************************************

>	void ColourListComponent::AddComponentValue(char *ColDef, char *Format, 
												double ComponentValue, BOOL Inherited)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	05/12/94
	Inputs:		ColDef - the current colour definition string, which this routine should
						 append the component value to.
				Format - the printf format to use when converting the value to ASCII.
				ComponentValue - the value to add to the string.
				Inherited - TRUE => This component is inherited, so just output a '-'
						   FALSE => This component is not inherited, so output the
									actual value to the string
	Outputs:	ColDef - the updated colour definition string, with the value converted to 
						 ASCII (taking into account the Inherited flag), and appended (with 
						 a leading space so the values don't join together).
	Purpose:	Add a colour component value to a colour definition string.  This is used
				to build up the entries in the EPS colour table.  It also centralises the
				syntax of inherited components.
	Errors:		-
	SeeAlso:	ColourListComponent::SaveColourAndChildren

********************************************************************************************/

void ColourListComponent::AddComponentValue( PTSTR ColDef, PCTSTR Format, 
											double ComponentValue, BOOL Inherited)
{
	// Construct the colour component value
	TCHAR				CompVal[20];

	// If this is a linked colour, and this component is inherited, then just add a '-'.
	if (Inherited)
	{
		camStrcpy( CompVal, _T("-") );
	}
	else
	{
		// We have to output the component....
		camSnprintf( CompVal, 20, const_cast<TCHAR *>(Format), ComponentValue );
	}

	// Add the value onto the end of the string
	camStrcat( ColDef, _T(" ") );
	camStrcat( ColDef, CompVal );
}



/********************************************************************************************

>	BOOL ColourListComponent::ColourOrChildIsShade(IndexedColour *pCol)

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	7/9/95
	Inputs:		pCol - The (root) colour to check

	Returns:	TRUE if this colour or a descendant is a Shade colour

	Purpose:	To determine if a colour is a Shade or has descendants which are Shades.

********************************************************************************************/

BOOL ColourListComponent::ColourOrChildIsShade(IndexedColour *pCol)
{
	// Check if this colour exists
	if (pCol->IsDeleted())
		return(FALSE);

	// Check if this colour is a shade
	if (pCol->GetType() == COLOURTYPE_TINT && pCol->TintIsShade())
		return(TRUE);

	// If this has no children, then no point in scanning further
	if (!pCol->HasLinkedChildren())
		return(FALSE);


	// Ask all the named colours that are immediate children of this colour
	IndexedColour *pChild = (IndexedColour *) pIndexedColours->GetHead();

	while (pChild != NULL)
	{
		if (!pChild->IsDeleted() && pChild->FindLinkedParent() == pCol)
		{
			// Found a child - recurse on it
			if (ColourOrChildIsShade(pChild))
				return(TRUE);
		}

		// Try the next colour
		pChild = (IndexedColour *) pIndexedColours->GetNext(pChild);
	}

	// Get all the unnamed colours that are immediate children of this colour
	List *pUnnamedList = pIndexedColours->GetUnnamedColours();
	pChild = (IndexedColour *) pUnnamedList->GetHead();

	while (pChild != NULL)
	{
		if (!pChild->IsDeleted() && pChild->FindLinkedParent() == pCol)
		{
			// Found a child - recurse on it
			if (ColourOrChildIsShade(pChild))
				return(TRUE);
		}

		// Try the next colour
		pChild = (IndexedColour *) pUnnamedList->GetNext(pChild);
	}

	return(FALSE);
}



// Simple macro to make the code in SaveColourAndChildren() a bit neater.
#define LINKED(ID) (Linked && pCol->InheritsComponent((ID)))

/********************************************************************************************

>	BOOL ColourListComponent::SaveColourAndChildren(IndexedColour *pCol, EPSExportDC *pDC, 
												BOOL CamelotEPS, INT32 NestingLevel = 0,
												BOOL SaveShades = FALSE)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	05/12/94
	Inputs:		pCol		- The (root) colour to save
				pDC			- The EPS export DC to save to
				CamelotEPS	- TRUE if exporting Camelot EPS
				NestingLevel- The nesting level of tint/shade/link colours. Used in
							  recursion - external callers should pass in 0
				SaveShades	- Indicates if Shades and their children should be saved. Used
							  in version 1.1 CamelotEPS to save out 2 colour tables, the
							  second of which includes the shades. (In this way, we could
							  retain load-compatability with older versions)
	Outputs:	-
	Returns:	-
	Purpose:	Save out an indexed colour to an EPS file, and all the colours that rely
				on it, i.e. any other indexed colours which are tints of, or links to, this
				colour.
	Errors:		-
	SeeAlso:	-

********************************************************************************************/

BOOL ColourListComponent::SaveColourAndChildren(IndexedColour *pCol, EPSExportDC *pDC, 
												BOOL CamelotEPS, INT32 NestingLevel,
												BOOL SaveShades)
{
#ifdef DO_EXPORT

	// (Jason 27/10/95) If the colour is unnamed and it's not actually used anywhere,
	// don't bother saving it. This optimises out temporary locals that are no longer
	// needed. At the worst, if something goes horribly wrong, this just means that
	// some locals might turn up as CMYK definitions on reloading, but this shouldn't
	// cause any problems unless something deeply scary has happened to the colour system.
	if (!pCol->IsNamed() && !pCol->IsInUse())
		return(TRUE);

	// Check for silly recursion errors	[not that you can get circular references with
	// the amazingly strict and careful checking done by the IndexedColour class - JW ;-]
	ERROR2IF(NestingLevel > 200, FALSE, "Rampant linked colour nesting detected!");

	// First, save out this indexed colour.
	ColourModel Model = pCol->GetColourModel();

	// Buffer to build up colour defs in.
	TCHAR ColDef[256];
	camStrcpy(ColDef, _T("%%+"));

	// Buffer for temporary strings
	TCHAR TmpBuf[256];

	// Get information on the colour - ask for its full identifier rather than just the name,
	// so we get a unique id for unnamed colours rather than just "Local colour"
	ColourGeneric GenCol;
	IndexedColourType ColType = pCol->GetType();
	pCol->GetSourceColour(&GenCol);
	TCHAR *ColName = (TCHAR *) (*(pCol->GetName(TRUE)));

	// Special check - Shades are only properly preserved in CamelotEPS. In all others, they
	// are treated as unlinked, normal colours, so that they will be read happily.
	if (!CamelotEPS && ColType == COLOURTYPE_TINT && pCol->TintIsShade())
	{
		ColType = COLOURTYPE_NORMAL;
	}

	// If we shouldn't be saving shade colours or their children on this pass, then don't
	// do anything for them this time.
	if (!SaveShades && ColType == COLOURTYPE_TINT && pCol->TintIsShade())
		return(TRUE);

	// If saving shades, then don't bother with non-shade colours which have no children, as
	// they do not need to be output.
	if (SaveShades && (ColType != COLOURTYPE_TINT || !pCol->TintIsShade()) && !pCol->HasLinkedChildren())
		return(TRUE);

	// Check for tints
	if (ColType == COLOURTYPE_TINT)
	{
		FIXED24 TintVal(0.0);
		FIXED24 ShadeVal(0.0);

		// Add tint identifier to colour definition
		if (pCol->TintIsShade())
		{
			camStrcat(ColDef, _T("d"));		// Is a shaDe
			TintVal = pCol->GetShadeValueY();		// Note that it is written out as "Y X"
			ShadeVal = pCol->GetShadeValueX();		// to make backward compatability easier
		}
		else
		{
			camStrcat(ColDef, _T("t"));		// Is a Tint
			TintVal = pCol->GetTintValue();
		}

		ERROR3IF(NestingLevel < 1, "Bad nesting when saving a tint/shade colour");

		// Get tint/shade value as an integer in range 0 - 100.
		INT32 Tint = (INT32) ((TintVal.MakeDouble() * 100.0) + ((TintVal < 0) ? -0.5 : 0.5));
		INT32 Shade = (INT32) ((ShadeVal.MakeDouble() * 100.0) + ((ShadeVal < 0) ? -0.5 : 0.5));

		if (NestingLevel > 1)
		{
			// Write out the nesting level
			camSnprintf(TmpBuf, 256, _T(" %d"), NestingLevel);
			camStrcat(ColDef, TmpBuf);
		}

		// Add the colour name and tint value
		if (pCol->TintIsShade())
			camSnprintf(TmpBuf, 256, _T(" (%s) %d %d"), ColName, Tint, Shade);
		else
			camSnprintf(TmpBuf, 256, _T(" (%s) %d"), ColName, Tint);
			camStrcat(ColDef, TmpBuf);
	}
	else
	{
		// Is this a linked colour?
		BOOL Linked = (ColType == COLOURTYPE_LINKED);

		// We only do linked colours in CamelotEPS
		Linked = Linked && CamelotEPS;

		
		if (Linked)
		{
			// Mark this as a linked colour
			camStrcat(ColDef, _T("l"));
		}
		else if (CamelotEPS && (ColType == COLOURTYPE_SPOT))
		{
			// Mark this as a spot colour
			camStrcat(ColDef, _T("s"));
		}

		// Save out colour model, nesting level and colour name
		switch (Model)
		{
			case COLOURMODEL_RGBT:
				camStrcat(ColDef, _T("r"));
				break;

			case COLOURMODEL_HSVT:
				camStrcat(ColDef, _T("h"));
				break;

			case COLOURMODEL_CMYK:
				camStrcat(ColDef, _T("c"));
				break;

			case COLOURMODEL_GREYT:
				// Special case - only Camelot can handle greyscales - ArtWorks can't.
				if (CamelotEPS)
					camStrcat(ColDef, _T("g"));
				else
					camStrcat(ColDef, _T("r"));
				break;

			default:
				break;
		}

		// Add nesting level, if needed
		if (NestingLevel > 1)
		{
			// Write out the nesting level
			camSnprintf(TmpBuf, 256, _T(" %d"), NestingLevel);
			camStrcat(ColDef, TmpBuf);
		}

		// Add colour name
		camStrcat(ColDef , _T(" ("));
		camStrcat(ColDef, ColName);
		camStrcat(ColDef, _T(")"));

		// Now write out the colour component values...
		switch (Model)
		{
			case COLOURMODEL_RGBT:
				// Now add the RGB components.
				ColourRGBT *pRGBT;
				pRGBT = (ColourRGBT *) &GenCol;

				AddComponentValue(ColDef, _T("%.3f"), pRGBT->Red.MakeDouble(),   LINKED(1));
				AddComponentValue(ColDef, _T("%.3f"), pRGBT->Green.MakeDouble(), LINKED(2));
				AddComponentValue(ColDef, _T("%.3f"), pRGBT->Blue.MakeDouble(),  LINKED(3));
				break;

			case COLOURMODEL_HSVT:
				// Now add the HSV components.
				ColourHSVT *pHSVT;
				pHSVT = (ColourHSVT *) &GenCol;

				AddComponentValue(ColDef, _T("%.1f"), pHSVT->Hue.MakeDouble() * 360.0, LINKED(1));
				AddComponentValue(ColDef, _T("%.1f"), pHSVT->Saturation.MakeDouble() * 100.0, LINKED(2));
				AddComponentValue(ColDef, _T("%.1f"), pHSVT->Value.MakeDouble() * 100.0, LINKED(3));
				break;

			case COLOURMODEL_CMYK:
				// Now add the CMYK components.
				ColourCMYK *pCMYK;
				pCMYK = (ColourCMYK *) &GenCol;

				AddComponentValue(ColDef, _T("%.3f"), pCMYK->Cyan.MakeDouble(),    LINKED(1));
				AddComponentValue(ColDef, _T("%.3f"), pCMYK->Magenta.MakeDouble(), LINKED(2));
				AddComponentValue(ColDef, _T("%.3f"), pCMYK->Yellow.MakeDouble(),  LINKED(3));
				AddComponentValue(ColDef, _T("%.3f"), pCMYK->Key.MakeDouble(),     LINKED(4));
				break;

			case COLOURMODEL_GREYT:
				// ArtWorks doesn't have explicit greyscale colours - use RGB model.
				ColourGreyT *pGreyT;
				pGreyT = (ColourGreyT *) &GenCol;
				double Intensity;
				Intensity = pGreyT->Intensity.MakeDouble();
				if (CamelotEPS)
				{
					// General greyscale format...just add the intensity component
					AddComponentValue(ColDef, _T("%.3f"), Intensity, LINKED(1));
				}
				else
				{
					// Fake a greyscale for ArtWorks with an RGB colour
					// where R = G = B.
					for (INT32 i = 1; i <= 3; i++)
					{
						AddComponentValue(ColDef, _T("%.3f"), Intensity, FALSE);
					}
				}
				break;

			default:
				ERROR3("Unknown colour type found in EPS export!");
				break;
		}
	}

	// Output colour definition to the EPS file
	pDC->OutputToken(ColDef);
	pDC->OutputNewLine();


	// (Jason 27/10/95) If it doesn't have linked children, don't recurse.
	// On large files, this saves a *lot* of time (O(n*n) becomes O(n)), because
	// (a) linked colours are only usually used sporadically, and (b) local colours,
	// which make up the bulk of saved colours, cannot have any children.
	if (!pCol->HasLinkedChildren())
		return(TRUE);


	// ---------- recurse ----------


	// Now recurse to save out any children of this colour (links or tints)...

	// Get all the named colours that are immediate children of this colour
	IndexedColour *pChild = (IndexedColour *) pIndexedColours->GetHead();

	while (pChild != NULL)
	{
		if (!pChild->IsDeleted() && pChild->FindLinkedParent() == pCol)
		{
			// Found a child - save out via recursion so we save all its descendants in the
			// right order...
			SaveColourAndChildren(pChild, pDC, CamelotEPS, NestingLevel + 1, SaveShades);
		}

		// Try the next colour
		pChild = (IndexedColour *) pIndexedColours->GetNext(pChild);
	}

	// Get all the unnamed colours that are immediate children of this colour
	List *pUnnamedList = pIndexedColours->GetUnnamedColours();

	pChild = (IndexedColour *) pUnnamedList->GetHead();

	while (pChild != NULL)
	{
		if (!pChild->IsDeleted() && pChild->FindLinkedParent() == pCol)
		{
			// Found a child - save out via recursion so we save all its descendants in the
			// right order...
			SaveColourAndChildren(pChild, pDC, CamelotEPS, NestingLevel + 1, SaveShades);
		}

		// Try the next colour
		pChild = (IndexedColour *) pUnnamedList->GetNext(pChild);
	}
#endif
	return TRUE;
}


/********************************************************************************************

>	ProcessEPSResult ColourListComponent::ProcessEPSComment(EPSFilter *pFilter, 
														    const char *pComment)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	02/08/94
	Inputs:		pFilter - the EPS filter that is being used to import a file.
				pComment - pointer to the comment to process.
	Returns:	EPSCommentUnknown	 - This EPS comment is not recognised by the document
									   component.
				EPSCommentError		 - This EPS comment was recognised by this document
									   component, but it contained an error.
				EPSCommentOK		 - This EPS comment was recognised as a legal comment by 
									   this document component, and was processed
									   successfully.
	Purpose:	Process an EPS comment - if this is a colour table comment, this component
				will claim it and try to decode it.

	Notes:		IMPORTANT
				There is a new colour field (which should only be put in a JWColourTable
				in CamelotEPS) which starts a comment line with "%%+x". The remainder of the
				line is undefined, but is treated as a valid line. This will make it possible
				to add data to the colour list in future without losing backward compatability
				or having to add yet another colour table type!
				If you use this, make sure your code happily *ignores* unknown x extensions.

	Errors:		Badly formed EPS comment.
	SeeAlso:	DocComponent::ProcessEPSComment

********************************************************************************************/

ProcessEPSResult ColourListComponent::ProcessEPSComment(EPSFilter *pFilter, 
														PCTSTR pComment)
{
	if (pFilter->IsKindOf(CC_RUNTIME_CLASS(ArtWorksEPSFilter)))
	{
		// Is it a Camelot specific filter?
		BOOL CamelotEPS = pFilter->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSFilter));

		// ArtWorks EPS (or derivative)
		if (camStrncmp(pComment, _T("%%AWColourTable"), 15) == 0)
		{
			// Found a colour table
			return EPSCommentOK;
		}
		else if (camStrncmp(pComment, _T("%%JWColourTable"), 15) == 0)
		{
			// Found a version 1.1 extended colour table
			return EPSCommentOK;			
		}
		else if (camStrncmp(pComment, _T("%%+"), 3) == 0)
		{
			// Found a colour - add it to the colour list for the document.

			// Take a copy of this comment
			TCHAR Comment[256];
			camStrcpy(Comment, pComment);

			// Find out the colour model (c, h, r, or t)
			INT32 i = 3;
			TCHAR ColModel = Comment[i++];

			// Check for special types (NB a colour cannot be both a spot colour and
			// a linked colour).
			NewColourInfo ColourInfo;
			BOOL Linked = FALSE;

			// Is it a spot colour?
			if  (ColModel == 's')
			{
				ColourInfo.Type = COLOURTYPE_SPOT;
				ColModel = Comment[i++];
			}
			else if (ColModel == 'l')
			{
				// It's a link, then find out the colour model of the linked colour.
				Linked = TRUE;
				ColourInfo.Type = COLOURTYPE_LINKED;
				ColModel = Comment[i++];
			}

			// If a tint/shade or link, find the nesting level, if any
			INT32 ColourNesting = 0;
			if ((ColModel == 't') || (ColModel == 'd') || Linked)
			{
				// Skip until we find a digit, a '(' or a terminator
				while (!isdigit(Comment[i]) && (Comment[i] != '(') && (Comment[i] != 0))
					i++;

				// Is there a nesting level?
				if (isdigit(Comment[i]))
				{
					// Yes - extract it and skip past it.
					ColourNesting = camAtol(Comment+i);

					while (isdigit(Comment[i]))
						i++;
				}
				else
				{
					// Must be level 1
					ColourNesting = 1;
				}
			}

			// Do we need to alter the link context?
			if (ColourNesting == 0)
			{
				// Normal colour
				pNewColours->RestoreContextTo(0);
			}
			else if (ColourNesting <= LinkNesting)
			{
				// Falling back to a previous nesting level - restore context to one
				// less than the nesting of this link/tint
				// (because we want to link/tint the colour one level below this one
				// in the nesting).
				LinkNesting = ColourNesting - 1;
				pNewColours->RestoreContextTo(LinkNesting);
			}

			// Find the colour name
			while ((Comment[i] != '(') && (Comment[i] != 0))
				i++;

			// Got it - copy it out of the string (skip the opening parenthesis)
			TCHAR ColName[128];
			i = ExtractString(Comment, i+1, ColName);
			String_64 ColNameS = ColName;

			// Copied the name - skip any whitespace
			while (((Comment[i] == ' ') || (Comment[i] == '\t')) &&
				   (Comment[i] != 0))
			{
				i++;
			}
			
			// Check for the overprint flag
			if (Comment[i] == 'o')
			{
				// Ignore it for now...
				i++;
				while (((Comment[i] == ' ') || (Comment[i] == '\t')) &&
					   (Comment[i] != 0))
				{
					i++;
				}
			}


			// Validate the colour model for this filter.
			if ((ColModel != 'r') && (ColModel != 'c') && 			// Rgb, Cmyk
			    (ColModel != 'h') && (ColModel != 't'))				// Hsv, Tint
			{
				// Reject outright if this is an ArtWorks file
				if (!CamelotEPS)
				{
					pFilter->HandleEPSError();
					return EPSCommentSyntaxError;
				}
			}

			// Do we need to save the context before adding this colour?
			if (Linked || (ColModel == 't') || (ColModel == 'd'))
			{
				pNewColours->SaveContext();
				LinkNesting++;
			}

			// Read the colour components according to the colour model.
			switch (ColModel)
			{
				case 'r':
				case 'R':
					{
						ColourRGBT NewRGBT;
						ReadEPS_RGB(&NewRGBT, Comment + i, &ColourInfo);
						if (!pNewColours->AddColour(&ColNameS, &NewRGBT, &ColourInfo))
							return EPSCommentSystemError;
					}
					break;

				case 'c':
					{
						ColourCMYK NewCMYK;
						ReadEPS_CMYK(&NewCMYK, Comment + i, &ColourInfo);
						if (!pNewColours->AddColour(&ColNameS, &NewCMYK, &ColourInfo))
							return EPSCommentSystemError;
					}
					break;

				case 'h':
				case 'H':
					{
						ColourHSVT NewHSVT;
						ReadEPS_HSV(&NewHSVT, Comment + i, &ColourInfo);
						if (!pNewColours->AddColour(&ColNameS, &NewHSVT, &ColourInfo))
							return EPSCommentSystemError;
					}
					break;

				case 't':		// Tint
					{
						UINT32 Tint = ReadEPS_Tint(Comment + i);

						if (!pNewColours->AddTint(&ColNameS, Tint))
							return EPSCommentSystemError;
					}
					break;

				case 'd':		// Shade - saved in same format as tint, so re-use ReadEPS_Tint method
					{
						INT32 ShadeX;
						INT32 ShadeY;
						ReadEPS_Shade(Comment + i, &ShadeX, &ShadeY);

						if (!pNewColours->AddShade(&ColNameS, ShadeX, ShadeY))
							return EPSCommentSystemError;
					}
					break;

				case 'G':
				case 'g':
					{
						ColourGreyT NewGreyT;
						ReadEPS_Grey(&NewGreyT, Comment + i, &ColourInfo);

						// Bodge for version 2
						// We really want black to be defined as CMYK so that it colour separates
						// more cleanly (and also merges on import better with new docs). Prior to v2,
						// the default black was defined as a greyscale so we sit on it during import
						// and turn it into a CMYK colour.
						if (NewGreyT.Intensity == 0 && ColNameS == String_64(TEXT("Black")))
						{
							ColourCMYK Bodge;
							Bodge.Cyan = Bodge.Magenta = Bodge.Yellow = 0;
							Bodge.Key = 1.0;

							if (!pNewColours->AddColour(&ColNameS, &Bodge, &ColourInfo))
								return EPSCommentSystemError;
						}
						else
						{
							if (!pNewColours->AddColour(&ColNameS, &NewGreyT, &ColourInfo))
								return EPSCommentSystemError;
						}
					}
					break;
			}

			// Parsed this colour ok.
			return EPSCommentOK;
		}
	}
	// Ignore all other comments
	return EPSCommentUnknown;
}


/********************************************************************************************

>	INT32 ColourListComponent::ExtractString(const char *Comment, INT32 Start, char *String)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	07/08/94
	Inputs:		Comment - pointer to the comment.
				Start - offset into Comment of the first character of the string (not
						including the first opening parenthesis).
	Outputs:	String - the PostScript string.
	Returns:	The offset to the first character after the closing parenthesis of
				the string.
	Purpose:	Copy a PostScript string out of the given EPS comment.  It handles
				nested parentheses - e.g. a string like (Hello (there)) will be
				correctly returned in String as "Hello (there)".
				The end of the comment is also taken as terminating the string.

********************************************************************************************/

INT32 ColourListComponent::ExtractString( PCTSTR Comment, INT32 Start, PTSTR String)
{
//	INT32 i = Start;
//	INT32 j = 0;
//	INT32 StringNesting = 1;
	
	// Look for the last closing Parenthesis in this string...
	const TCHAR		   *End = camStrrchr(Comment, ')');

	if ((End == NULL) || (End < (Comment + Start)))
	{
		// Something's gone wrong - don't extract string and put a warning where the colour name
		// should be.
		camStrcpy( String, _T("Colour Import Error") );
		return Start;
	}

	// Copy the colour name from the comment into the string provided, and NULL
	// terminate it.
	INT32 NameLength = End - Comment;
	NameLength -= Start;

	camStrncpy( String, Comment + Start, NameLength );
	String[NameLength] = 0;

	// Return the next character position after the string's closing parenthesis.
	return Start + NameLength + 1;
}

/********************************************************************************************

>	void ColourListComponent::ReadEPS_RGB(ColourRGBT *pCol, char *pComment, 
									  NewColourInfo *pColourInfo)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	03/08/94
	Inputs:		pCol - the colour to initialise from the comment.
				pComment - pointer to the comment fields to use.
				pColourInfo - if NULL, then this is not a linked colour
							  if non-NULL, then this is a linked colour, and the fields
							    should be filled in according to the inheritance flags
							    found in the colour definition.
	Purpose:	Read the RGB components from an ArtWorks EPS colour table comment, and
				initialise an indexed colour object using these values.
				The comment passed in is expected to be a pointer to the character just
				after the colour name/overprint flag, i.e. the start of the colour
				description.  Leading white space is permissible.
	SeeAlso:	ColourListComponent::ReadEPS_CMYK; ColourListComponent::ReadEPS_HSV;
				ColourListComponent::ReadEPS_Tint

********************************************************************************************/

void ColourListComponent::ReadEPS_RGB( ColourRGBT *pCol, PTSTR pComment, 
								  NewColourInfo *pColourInfo )
{
	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	PTSTR pszTokMark = NULL ;
	PTSTR Value = camStrtok(pComment, _T(" \t"), &pszTokMark);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-") ) == 0))
			pColourInfo->Inherits[0] = TRUE;
		else
			pCol->Red = camStrtof( Value, &pszTokMark );
	}

	Value = camStrtok( NULL, _T(" \t"), &pszTokMark );
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-") ) == 0))
			pColourInfo->Inherits[1] = TRUE;
		else
			pCol->Green = camStrtof( Value, &pszTokMark );
	}

	Value = camStrtok( NULL, _T(" \t"), &pszTokMark );
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-") ) == 0))
			pColourInfo->Inherits[2] = TRUE;
		else
			pCol->Blue = camStrtof( Value, &pszTokMark );
	}

	// No transparency
	pCol->Transparent = 0.0;
}

/********************************************************************************************

>	void ColourListComponent::ReadEPS_CMYK(ColourCMYK *pCol, char *pComment, 
									   NewColourInfo *pColourInfo)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	03/08/94
	Inputs:		pCol - the colour to initialise from the comment.
				pComment - pointer to the comment fields to use.
	Purpose:	Read the CMYK components from an ArtWorks EPS colour table comment, and
				initialise an indexed colour object using these values.
				The comment passed in is expected to be a pointer to the character just
				after the colour name/overprint flag, i.e. the start of the colour
				description.  Leading white space is permissible.
	SeeAlso:	ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_HSV;
				ColourListComponent::ReadEPS_Tint

********************************************************************************************/

void ColourListComponent::ReadEPS_CMYK(ColourCMYK *pCol, PTSTR pComment, 
								   NewColourInfo *pColourInfo)
{
	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	TCHAR *State = NULL;
	TCHAR *Value = camStrtok(pComment, _T(" \t"), &State);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-")) == 0))
			pColourInfo->Inherits[0] = TRUE;
		else
			pCol->Cyan = camAtof(Value);
	}

	Value = camStrtok(NULL, _T(" \t"), &State);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-")) == 0))
			pColourInfo->Inherits[1] = TRUE;
		else
			pCol->Magenta = camAtof(Value);
	}

	Value = camStrtok(NULL, _T(" \t"), &State);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-")) == 0))
			pColourInfo->Inherits[2] = TRUE;
		else
			pCol->Yellow = camAtof(Value);
	}

	Value = camStrtok(NULL, _T(" \t"), &State);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-")) == 0))
			pColourInfo->Inherits[3] = TRUE;
		else
			pCol->Key = camAtof(Value);
	}

}

/********************************************************************************************

>	void ColourListComponent::ReadEPS_HSV(ColourHSVT *pCol, char *pComment,
									  NewColourInfo *pColourInfo)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	03/08/94
	Inputs:		pCol - the colour to initialise from the comment.
				pComment - pointer to the comment fields to use.
	Purpose:	Read the HSV components from an ArtWorks EPS colour table comment, and
				initialise an indexed colour object using these values.
				The comment passed in is expected to be a pointer to the character just
				after the colour name/overprint flag, i.e. the start of the colour
				description.  Leading white space is permissible.
	SeeAlso:	ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_CMYK;
				ColourListComponent::ReadEPS_Tint

********************************************************************************************/

void ColourListComponent::ReadEPS_HSV(ColourHSVT *pCol, PTSTR pComment,
								  NewColourInfo *pColourInfo)
{
	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	TCHAR *State = NULL;
	TCHAR *Value = camStrtok(pComment, _T(" \t"), &State);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-")) == 0))
			pColourInfo->Inherits[0] = TRUE;
		else
			pCol->Hue = camAtof(Value) / 360.0;
	}

	Value = camStrtok(NULL, _T(" \t"), &State);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-")) == 0))
			pColourInfo->Inherits[1] = TRUE;
		else
			pCol->Saturation = camAtof(Value) / 100.0;
	}

	Value = camStrtok(NULL, _T(" \t"), &State);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-")) == 0))
			pColourInfo->Inherits[2] = TRUE;
		else
			pCol->Value = camAtof(Value) / 100.0;
	}

	// No transparency
	pCol->Transparent = 0.0;

}

/********************************************************************************************

>	void ColourListComponent::ReadEPS_Grey(ColourGreyT *pCol, char *pComment,
									   NewColourInfo *pColourInfo)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	03/08/94
	Inputs:		pCol - the colour to initialise from the comment.
				pComment - pointer to the comment fields to use.
	Purpose:	Read the HSV components from an ArtWorks EPS colour table comment, and
				initialise an indexed colour object using these values.
				The comment passed in is expected to be a pointer to the character just
				after the colour name/overprint flag, i.e. the start of the colour
				description.  Leading white space is permissible.
	SeeAlso:	ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_CMYK;
				ColourListComponent::ReadEPS_Tint

********************************************************************************************/

void ColourListComponent::ReadEPS_Grey(ColourGreyT *pCol, PTSTR pComment,
								   NewColourInfo *pColourInfo)
{
	BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);

	TCHAR * State=NULL;
	TCHAR *Value = camStrtok(pComment, _T(" \t"), &State);
	if (Value != NULL)
	{
		if (Linked && (camStrcmp(Value, _T("-")) == 0))
			pColourInfo->Inherits[0] = TRUE;
		else
			pCol->Intensity = camAtof(Value);
	}

	// Clear the reserved words to 0.
	pCol->Reserved1 = 0.0;
	pCol->Reserved2 = 0.0;

	// No transparency
	pCol->Transparent = 0.0;
}

/********************************************************************************************

>	void ColourListComponent::ReadEPS_Tint(char *pComment)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	07/08/94
	Inputs:		pComment - pointer to the comment fields to use.
	Purpose:	Read the tint value from an ArtWorks style tint colour definition comment.

				(OR Read the shade value out of a CamelotEPS shade ("d") comment. Shades
				are stored in identical; format to tints)

	SeeAlso:	ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_CMYK;
				ColourListComponent::ReadEPS_HSVT

********************************************************************************************/

UINT32 ColourListComponent::ReadEPS_Tint( PTSTR pComment )
{
	PTSTR pszTokMark = NULL;
	PTSTR Value = camStrtok( pComment, _T(" \t"), &pszTokMark );
	INT32 Tint = 0;
	if (Value != NULL)
	{
		// Get the tint value
		Tint = camStrtol( Value, &pszTokMark, 10 );
		if (Tint < 0)
			Tint = 0;
	}

	return (UINT32) Tint;
}



/********************************************************************************************

>	void ColourListComponent::ReadEPS_Shade(char *pComment, INT32 *ResultX, INT32 *ResultY)

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	13/10/95
	Inputs:		pComment - pointer to the comment fields to use.

	Outputs:	ResultX,ResultY - returned with the shade values

	Purpose:	Read the shade values from a Camelot shade colour definition comment.

				(OR Read the shade value out of a CamelotEPS shade ("d") comment. Shades
				are stored in identical; format to tints)

	Notes:		Old style shades had only one relative value (Y). If this is missing,
				then an appropriate default is chosen such that it all still works.

	SeeAlso:	ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_CMYK;
				ColourListComponent::ReadEPS_HSVT

********************************************************************************************/

void ColourListComponent::ReadEPS_Shade( PTSTR pComment, INT32 *ResultX, INT32 *ResultY)
{
	PTSTR pszTokMark = NULL;
	PTSTR Value = camStrtok( pComment, _T(" \t"), &pszTokMark );
	INT32  Val = 0;
	if( Value != NULL )
		Val = camStrtol( Value, &pszTokMark, 10 );

	*ResultY = (INT32)Val;

	Value = camStrtok( NULL, _T(" \t"), &pszTokMark );
	if (Value != NULL)
	{
		Val = camStrtol( Value, &pszTokMark, 10 );

TRACEUSER( "Jason", _T("Load new shade %ld %ld\n"), Val, (INT32)*ResultY);
	}
	else
	{
		// There is no second token - it must be in the old save format
		// The old value was a 0-100 shade-to-black, so to convert into the new
		// format we just negate it. Happy Happy Bodge Bodge.
		*ResultY = -(*ResultY);
		
		// And set a sensible X value
		Val = 0;
TRACEUSER( "Jason", _T("Load OLD shade %ld %ld\n"), Val, (INT32)*ResultY);
	}

	*ResultX = (INT32)Val;
}




/********************************************************************************************

>	void ColourListComponent::EndOfEPSComment(EPSFilter *pFilter)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	02/08/94
	Inputs:		pFilter - the EPS filter that is being used to import a file.
	Purpose:	Informs the document component that the comment it has been decoding has
				now finished, and it should take whatever action required to act on
				the comment.
	SeeAlso:	DocComponent::EndOfPESComment

********************************************************************************************/

void ColourListComponent::EndOfEPSComment(EPSFilter *pFilter)
{
	// Do any cleanup we need to here after loading in a colour table...
}



/********************************************************************************************

>	IndexedColour *ColourListComponent::FindNamedColour(const char *pName, 
														DocColour *ColDef = NULL,
													    UINT32 Tint = 100,
													    BOOL Strict = FALSE)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	04/08/94
	Inputs:		pName - the name of the colour to find.
				ColDef - the colour definition that it should match.
				Tint - the tint value applied to ColDef (NB it should already have been
					   applied); 100 = same colour, 0 = white.

				Strict - not used (obsolete)

	Returns:	Pointer to the indexed colour that corresponds to the file's named colour;
				or NULL if the colour could not be found (the caller should fall back to
				   an immediate colour in this case).
	Purpose:	Given the name of an imported named colour, return the relevant indexed
				colour.  This allows attributes to be added when importing that use
				named colours.
				If ColDef is not NULL, then the Indexed colour found is checked to see
				if it agrees with the definition in ColDef - if not, then a new indexed
				colour is made, and a pointer to that is returned instead.  This means we
				can cope with brain-damaged formats that have two or more named colours
				with the same format.  It also makes it easy to cope with formats that
				use unnamed colours, as we just keep making colours called "Unnamed colour"
				or similar, and this function works it all out for us.

				If the named colour is not found, and ColDef is not NULL, then again a
				new Indexed colour is created, and a pointer to it is returned.

				NB. The name of the indexed colour returned MAY NOT have the same name as
				specified in pName, because it may clash with colours already in the
				document, and hence may have been mangled to make it unambiguous.

********************************************************************************************/

IndexedColour *ColourListComponent::FindNamedColour( PCTSTR pName, 
													DocColour *ColDef,
													UINT32 Tint,
													BOOL Strict)
{
	// Sanity check
	ENSURE(pNewColours != NULL, "Someone asked for an imported colour when there is no import going on!");

	if (pNewColours == NULL)
		return NULL;

	// Special case for tinted colours - if the Tint is not 100%, then we must look for
	// or create a tinted version of the colour.
	if (Tint != 100)
	{
		// Create a new name to indicate this is tinted
		String_64 NewName(pName);

		// Work out where to add the tint comment to the colour name.
		// Comment is of the form: " (xx% tint)", which is 11 characters long.
		INT32 Len = NewName.Length();
		if (Len > 50)
		{
			// This should give us enough room for our tint comment
			Len = 50;
		}

		TCHAR		   *pNewName = (TCHAR *)NewName;
		camSnprintf( pNewName + Len, 64 - Len, _T(" (%d%% tint)"), Tint );

		// Ok - we have a name - recurse so we can get a new colour (or use an existing
		// one created by this bit of code).
		return FindNamedColour(NewName, ColDef);
	}

	// Find the colour in the imported colour table.
	IndexedColour *pColour;
	PColourCMYK CMYK;
	ColDef->GetCMYKValue(&CMYK);
	pColour = pNewColours->GetColour( pName, &CMYK );

	// Is there one that fits the bill?
	if (pColour != NULL)
		return pColour;

	// Colour not found - can we make a new one?
	if (ColDef != NULL)
	{
		// Yes - add a new colour...

		// Make a proper definition:
		ColourCMYK FullCMYK;
		FullCMYK.Cyan    = FIXED24( ((double) CMYK.Cyan) 	/ 255.0 );
		FullCMYK.Magenta = FIXED24( ((double) CMYK.Magenta) / 255.0 );
		FullCMYK.Yellow  = FIXED24( ((double) CMYK.Yellow) 	/ 255.0 );
		FullCMYK.Key     = FIXED24( ((double) CMYK.Key) 	/ 255.0 );

		// And use it to add the colour
		String_64 NewName(pName);
		if (pNewColours->AddColour(&NewName, &FullCMYK))
		{
			// It worked - return the colour created
			return pNewColours->GetColour( pName, &CMYK );
		}
		else
		{
			// Failed to add a new colour
			return NULL;
		}
	}

	// Can't make a new one without a colour definition - give up.
	return NULL;
}


/********************************************************************************************

>	BOOL ColourListComponent::FindIdenticalColour(IndexedColour *pColour,
												  IndexedColour **pResult)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	07/08/94
	Inputs:		pColour - the colour to match with.
	Outputs:	pResult - pointer to the matching colour, if found;
						  NULL otherwise.
	Returns:	TRUE if a colour with this *name* was found in the document;
				FALSE if not.
	Purpose:	Find out if there is already a colour exactly the same as the one passed
				in in the existing colour list.  If so, return a pointer to it, otherwise
				return NULL.
				Also indicates whether or not a colour with this name already exists in the
				document, regardless of whether the colour data is the same.

********************************************************************************************/

BOOL ColourListComponent::FindIdenticalColour(IndexedColour *pColour,
											  IndexedColour **pResult)
{
	IndexedColour *pItem = (IndexedColour *) pIndexedColours->GetHead();

	BOOL FoundSameName = FALSE;

	// Get the name/ID for this colour. TRUE is passed in so that unnamed colours return
	// their unique id string rather than "Local colour"
	String_64 *Name1 = pColour->GetName(TRUE);

	while (pItem != NULL)
	{
		// Don't bother with deleted colours
		if (!pItem->IsDeleted())
		{
			// WEBSTER - markn 14/2/97
			// Introduced WEBSTER_IGNORE_NAME_MATCHING so that Webster can ignore the name when
			// trying to find an identical colour

			#if WEBSTER_IGNORE_NAME_MATCHING 
			if (pIndexedColours != NULL)
			{
				if (!pItem->IsDifferent(*pColour, COL_ACCURACY))
				{
					if (ColourSGallery::CanAddColourToGallery(pItem,pIndexedColours))
					{
						*pResult = pItem;
						return TRUE;
					}
				}
			}
			#else
			// Compare names
			String_64 *Name2 = pItem->GetName(TRUE);
			if ((*Name1) == (*Name2))
			{
				FoundSameName = TRUE;

				// Name is the same - what about colour model + definition?
				if (!pItem->IsDifferent(*pColour, COL_ACCURACY))
				{
					// The colour defn the same too - it's a match
					*pResult = pItem;
					return TRUE;
				}
			}
			#endif // WEBSTER_IGNORE_NAME_MATCHING 
		}

		// Try the next colour
		pItem = (IndexedColour *) pIndexedColours->GetNext(pItem);
	}

	// No match - tell caller whether we found one with the same name.
	*pResult = NULL;
	return FoundSameName;
}








/********************************************************************************************

>	IndexedColour *ColourListComponent::ExactMatchExists(IndexedColour *SourceColour)

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	18/10/94

	Inputs:		SourceColour - The colour to match
	Returns:	A pointer to the IndexedColour in this document which exactly matches the
				given SourceColour, or NULL if no matching colour exists.

	Purpose:	Determine if a colour is already available in the paste-destination document
				This allows us to merge IndexedColours on the clipboard with those in the
				target document when doing a paste operation.

	Notes:		Exact match means: Another non-deleted colour which is not IsDifferent
				and which has an identical (sortof - see below) name string.

				SPECIAL behaviour: The name string match now ignores digits on the end
				of the string. This is so that if you copy and paste "Red" such that the pasted
				colour is "Red 2", a subsequent paste will match the source "Red" and the
				destination "Red 2", rather than adding an identical "Red 3"!

				Unnamed colours will never match.

	SeeAlso:	ColourListComponent::CopyColourAcross

********************************************************************************************/

IndexedColour *ColourListComponent::ExactMatchExists(IndexedColour *SourceColour)
{
	// If it's an unnamed (local) colour, then we don't bother looking for a match
	if (!SourceColour->IsNamed())
		return(NULL);

	IndexedColour *pItem = (IndexedColour *) pIndexedColours->GetHead();

	// --- First check for any *exact* matches
	// Get the name/ID for this colour. TRUE is passed in so that unnamed colours return
	// their unique id string rather than "Local colour" (hmmm... we aren't checking 
	// unnamed colours, so this is a bit of a moot point! ;-)
	String_64 SourceName = *(SourceColour->GetName(TRUE));

	while (pItem != NULL)
	{
		if (!pItem->IsDeleted() && !pItem->IsDifferent(*SourceColour))	// not different, so check name
		{
			if (SourceName.CompareTo(*pItem->GetName(TRUE)) == 0)		// If has same name then...
				return(pItem);											// Return it as match
		}

		// Try the next colour
		pItem = (IndexedColour *) pIndexedColours->GetNext(pItem);
	}


	// --- Second, check for near-matches.
	// This is an exact match except it ignores the space and digits appended to a name
	// in the quest for a unique name. This means if the name "Red" is in use, and we paste
	// a different colour called "Red" it will add "Red 2" the first paste, but subsequent
	// pastes will match "Red 2" and simply merge with that colour (rather than adding Red 2
	// Red 3, Red 4, ect ad infinitum!)
	pItem = (IndexedColour *) pIndexedColours->GetHead();
	while (pItem != NULL)
	{
		if (!pItem->IsDeleted() && !pItem->IsDifferent(*SourceColour))			// not different, so check name
		{
			// Get the string as a TCHAR array so we can actually do something with it (grr)
			TCHAR *StrPtr = (TCHAR *) (*pItem->GetName(TRUE));

			// Find the zero terminator
			INT32 Index = 0;
			while (StrPtr[Index] != (TCHAR)'\0')
				Index++;

			// Now make index point at the last character
			Index -= 1;
			if (Index > 0)
			{
				if (UnicodeManager::IsDBCSLeadByte(StrPtr[Index-1]))
					Index -= 1;
			}

			// Scan backwards, skipping all digits that we find
			INT32 EndIndex = Index;
			while (Index > 0)
			{
				if (!StringBase::IsNumeric(StrPtr[Index]))
					break;

				Index -= 1;
				if (Index > 0)
				{
					if (UnicodeManager::IsDBCSLeadByte(StrPtr[Index-1]))
						Index -= 1;
				}
			}

			// Now, if we found digits, scan back over this char if it is a space
			if (Index > 0 && Index < EndIndex && StrPtr[Index] == (TCHAR)' ')
			{
				// Rightoh. This looks like an auto-generated unique-name, so does the text
				// without the unique-ness number match our name?
				String_64 ToCheck;
				pItem->GetName(TRUE)->Left(&ToCheck, Index);

				if (SourceName.CompareTo(ToCheck) == 0)
					return(pItem);					// Yep - the names match
			}
		}

		// Try the next colour
		pItem = (IndexedColour *) pIndexedColours->GetNext(pItem);
	}

	// No match was found for this colour
	return(NULL);
}



/********************************************************************************************

>	virtual BOOL ColourListComponent::StartComponentCopy();

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	10/9/94
	Inputs:		-
	Outputs:	-
	Returns:	TRUE if it succeeded. FALSE if the copy must be aborted
	Purpose:	This function gets called to prepare for a copy of indexed colours into
				the document. It sets up the various arrays and other thangs which the
				colour copy will need.
	Errors:		ENSURE failure if called when a component copy is already under way.
				Errors will be reported if memory is unavailable
	SeeAlso:	ColourListComponent::EndComponentCopy;
				ColourListComponent::AbortComponentCopy;
				ColourListComponent::CopyColourAcross

********************************************************************************************/

BOOL ColourListComponent::StartComponentCopy()
{
	// Make sure the fn has not been called before
	if (SourceColours != NULL || DestColours != NULL)
	{
		ERROR3("StartComponentCopy already called");
		return(TRUE);
	}

	ColourTableSize = 64;			// Start off with 64-entry table. This may grow if
									// we find we have a lot of colours to copy over

	SourceColours = (IndexedColour **) CCMalloc(ColourTableSize * sizeof(IndexedColour *));
	if (SourceColours == NULL)
	{
		InformError();				// Out of memory - inform the user
		return(FALSE);
	}

	DestColours = (IndexedColour **) CCMalloc((ColourTableSize+1) * sizeof(IndexedColour *));
	if (DestColours == NULL)
	{
		InformError();				// Out of memory - inform the user

		CCFree(SourceColours);		// And release our other memory - we can't use it now
		SourceColours = NULL;
		return(FALSE);
	}

	MergeColours = (BOOL *) CCMalloc(ColourTableSize * sizeof(BOOL));
	if (MergeColours == NULL)
	{
		InformError();				// Out of memory - inform the user

		CCFree(SourceColours);		// And release our other memory - we can't use it now
		CCFree(DestColours);
		SourceColours = DestColours = NULL;
		return(FALSE);
	}

	// Initialise the arrays
	for (INT32 i = 0; i < ColourTableSize; i++)
	{
		SourceColours[i] = DestColours[i] = NULL;
		MergeColours[i]  = FALSE;
	}

	DestColours[ColourTableSize] = NULL;	// And add a NULL terminator to dest. list

	return(TRUE);
}



/********************************************************************************************

>	virtual BOOL ColourListComponent::EndComponentCopy()

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	10/9/94

	Returns:	TRUE if it succeeded
	Purpose:	Will commit all changes made by doing the component copy, returning TRUE.
				Any new colours will be inserted as instructed by the InsertBefore parameter.
				If some colours will not be insterted because they were merged, then a report
				to this effect can be given if desired.

	Notes:		May be called multiple times - subsequent calls will be ignored

				Overrides the base class method. Calls an internal variant on this method.

	SeeAlso:	ColourListComponent::StartComponentCopy;
				ColourListComponent::AbortComponentCopy;
				ColourListComponent::CopyColourAcross

********************************************************************************************/

BOOL ColourListComponent::EndComponentCopy()
{
	return(ColourListComponent::EndComponentCopy(NULL, FALSE));
}



/********************************************************************************************

>	virtual BOOL ColourListComponent::EndComponentCopy(IndexedColour *InsertBefore,
														BOOL Report);

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	10/9/94
	Inputs:		InsertBefore - NULL to insert at the end of the colour list, else a pointer
				the the IndexedColour before which you wish to insert the colours.

				Report - FALSE to do it quietly, TRUE if you'd like a report given if any colours
				were merged (used by the colour gallery when copying colours, as merged colours
				will fail to appear in the chunk of copied colours, which can confuse the user)

	Returns:	TRUE if it succeeded
	Purpose:	Will commit all changes made by doing the component copy, returning TRUE.
				Any new colours will be inserted as instructed by the InsertBefore parameter.
				If some colours will not be insterted because they were merged, then a report
				to this effect can be given if desired.

	Notes:		May be called multiple times - subsequent calls will be ignored

				WARNING: This is NOT an override of the base class method. Be careful

	SeeAlso:	ColourListComponent::StartComponentCopy;
				ColourListComponent::AbortComponentCopy;
				ColourListComponent::CopyColourAcross

********************************************************************************************/

BOOL ColourListComponent::EndComponentCopy(IndexedColour *InsertBefore, BOOL Report)
{
	BOOL NeedToReport = FALSE;

	if (SourceColours != NULL)	// Free the source mapping array
	{
		CCFree(SourceColours);
		SourceColours = NULL;
	}

	if (DestColours != NULL)
	{
		// Add the colours in the 'Destination' array to the ColourList for the dest. doc.
		// We only add those colours which have not been merged with existing colours in the
		// destination list. The AddItem() call ensures their names are unique in this doc.
		INT32				i;
		for ( i = 0; i < ColourTableSize; i++)
		{
			if (DestColours[i] != NULL && !MergeColours[i])
			{
				if (InsertBefore == NULL || !DestColours[i]->IsNamed())
					pIndexedColours->AddItem(DestColours[i]);
				else
					pIndexedColours->InsertBefore(InsertBefore, DestColours[i]);
			}
		}

		// Now, remove all merged colours from the list of colours to be 'unhidden' for undo
		// NOTE that DestColours is guaranteed to be NULL terminated

		// We delete each merged colour from the list by copying the first valid list item
		// over the top of the merged item; we keep track of the valid list start with
		// 'ListStart'. Once finished, we pass any remainder of the array to UnHideColours
		INT32 ListStart = 0;
		for (i = 0; i < ColourTableSize; i++)
		{
			if (DestColours[i] == NULL)			// Stop at NULL terminator
				break;

			if (MergeColours[i] || !DestColours[i]->IsNamed())
			{
				// A merged or unnamed colour - copy list item '0' over it, so that we do not
				// try to do any undo record for it.
				DestColours[i] = DestColours[ListStart];
				DestColours[ListStart] = NULL;
				ListStart++;

				NeedToReport = TRUE;
			}
		}

		if (DestColours[ListStart] != NULL)		// If there are non-merged named colours, create undo
			ColourManager::UnHideColours(pIndexedColours, &DestColours[ListStart]);

		// Lose our workspace array of pointers to these colours
		CCFree(DestColours);
		DestColours = NULL;
	}

	if (MergeColours != NULL)	// Free the 'merged'-flag array
	{
		CCFree(MergeColours);
		MergeColours = NULL;
	}

	// If the caller wants us to, report (if necessary) that some of the colours
	// were not copied, as they were already present in the dest. doc
	if (Report && NeedToReport)
		InformMessage(_R(IDS_COLOURSMERGED), _R(IDS_OK));

	return(TRUE);
}



/********************************************************************************************

>	virtual void ColourListComponent::AbortComponentCopy();

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	10/9/94
	Inputs:		-
	Outputs:	-
	Returns:	-
	Purpose:	Will abort all changes made for component copies.
				This means that things such as the colours referenced by the nodes
				you have just copied do not exist, so you must clean up to the state
				the document was in before you strated copying.
	Errors:		-
	Notes:		May be called even if StartComponentCopy has not been called.
				May be called multiple times

	SeeAlso:	ColourListComponent::EndComponentCopy;
				ColourListComponent::AbortComponentCopy;
				ColourListComponent::CopyColourAcross

********************************************************************************************/

void ColourListComponent::AbortComponentCopy()
{
	// Clean up by deleting all the new indexedColours we created. We hope that by the
	// time we do this, all DocColours referencing these colours will have been vaped.
	if (DestColours != NULL)
	{
		for (INT32 i = 0; i < ColourTableSize; i++)
		{
			if (DestColours[i] != NULL && !MergeColours[i])
			{
				delete DestColours[i];
				DestColours[i] = NULL;
			}
		}
	}

	// And release our working arrays
	if (SourceColours != NULL)
	{
		CCFree(SourceColours);
		SourceColours = NULL;
	}

	if (DestColours != NULL)
	{
		CCFree(DestColours);
		DestColours = NULL;
	}

	if (MergeColours != NULL)
	{
		CCFree(MergeColours);
		MergeColours = NULL;
	}
}



/********************************************************************************************

>	INT32 ColourListComponent::ExtendTables(void)

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	28/11/94 (Separated from CopyColourAcross)
	Inputs:		-
	Outputs:	(The mapping arrays may have been moved by realloc)
	Returns:	-1 if it fails (it will have already reported the error
				else the index of the first free entry in the mapping tables

	Purpose:	Called by Component Copy routines to extend the size of the copy mapping
				tables (SourceColours[], DestColours[], and MergeColours[]). This returns
				the index of the first free entry in the new tables, or -1 if it fails.

	Errors:		Memory errors are reported immediately

	SeeAlso:	ColourListComponent::StartComponentCopy;
				ColourListComponent::AbortComponentCopy;
				ColourListComponent::EndComponentCopy

********************************************************************************************/

INT32 ColourListComponent::ExtendTables(void)
{
	INT32 i = ColourTableSize;	// Set the index to the first new array entry

	ColourTableSize += 64;		// Increase the size of our mapping arrays
	IndexedColour **TempArray;

	// Realloc the Source array, with error handling
	TempArray = (IndexedColour **) CCRealloc(SourceColours,
											ColourTableSize * sizeof(IndexedColour *));
	if (TempArray == NULL)
	{
		InformError();
		return(-1);
	}

	SourceColours = TempArray;	// Realloc succeeded - set the new SourceColour ptr
	
	// Realloc the Dest array, with error handling
	TempArray = (IndexedColour **) CCRealloc(DestColours,
											(ColourTableSize+1) * sizeof(IndexedColour *));
	if (TempArray == NULL)
	{
		InformError();
		return(-1);
	}

	DestColours = TempArray;	// Realloc succeeded - set the new DestColour ptr

	// Realloc the 'Merged'-flag array, with error handling
	BOOL *TempBoolArray = (BOOL *) CCRealloc(MergeColours,
											ColourTableSize * sizeof(BOOL));
	if (TempBoolArray == NULL)
	{
		InformError();
		return(-1);
	}

	MergeColours = TempBoolArray;	// Realloc succeeded - set the new MergeColour ptr

	// Initialise the new portions of the arrays
	for (INT32 j = i; j < ColourTableSize; j++)
	{
		SourceColours[j] = DestColours[j] = NULL;
		MergeColours[j] = FALSE;
	}

	DestColours[ColourTableSize] = NULL;	// And add a NULL terminator to dest. list

	return(i);
}



/********************************************************************************************

>	IndexedColour *ColourListComponent::MapColour(IndexedColour *SourceColour,
													BOOL *AlreadyThere = NULL,
													BOOL SourceIsUnique = FALSE)

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	29/10/94

	Inputs:		SourceColour - pointer to an IndexedColour to map

				(AlreadyThere is an output only)

				SourceIsUnique - FALSE (the default) if you're copying existing document
								 colours around, and therefore could attempt to copy the
								 same colour multiple times.

								 TRUE if you can guarantee that this colour will only be
								 copied once. This is used only for copying library colours
								 into a document in the colour gallery (where it uses a temporary
								 IndexedColour, which causes problems when several different
								 colours accidentally map to the same temporary memory allocation,
								 thus causing rampant incorrect colour merging to occur).

	Outputs:	AlreadyThere - (if non-NULL) is filled in with TRUE if the colour was merged
				or FALSE if a new colour had to be created.

	Returns:	NULL if it fails (the error will have been reported)
				Otherwise, a pointer to the IndexedColour resulting from the mapping

	Purpose:	Used internally in ColourListComponent Component Copy routines.
				This method keeps track of mappings between source document and destination
				document colours. It determines the mapping from source to dest, and returns
				the appropriate destination-docuemnt IndexedColour. This may be a new colour
				which will later be added to the destination document or a colour already in
				the dest. doc (merged colour). Once an IndexedColour is mapped, future calls
				to this method will be very efficient (a simple table search and lookup of
				the previous mapping)

	Notes:		This method is recursive. This allows it to cope with a chain of parent
				tint/link colours which may or may not be mapped already. Special care
				is taken to ensure that only destination-document references are left
				at the end of the copy operation (as obviously, references to the source
				doc are highly dangerous, and usually fatal)

	SeeAlso:	ColourListComponent::StartComponentCopy;
				ColourListComponent::AbortComponentCopy;
				ColourListComponent::EndComponentCopy

********************************************************************************************/

IndexedColour *ColourListComponent::MapColour(IndexedColour *SourceColour,
												BOOL *AlreadyThere, BOOL SourceIsUnique)
{
	if (AlreadyThere != NULL)	// Set a safe return value
		*AlreadyThere = FALSE;

	// First, check if the colour is already mapped; if so, just return its mapping
	// If SourceIsUnique, then we know no two source colours will never be the same,
	// and to fix a temporary-colour-reuse (2 colours in the same memory location)
	// problem in colour gallery library colour copies, we don't cache the mappings.
	// This is fine, because those copies only copy each colour once, so there is
	// no need to cache mappings for them anyway.
	if (!SourceIsUnique)
	{
		INT32 i = 0;
		while (i < ColourTableSize && SourceColours[i] != NULL && SourceColours[i] != SourceColour)
			i++;

		if (i < ColourTableSize && SourceColours[i] == SourceColour)
		{
			// If it was merged, return a value indicating that	case
			if (AlreadyThere != NULL && MergeColours[i])
				*AlreadyThere = TRUE;

			return(DestColours[i]);
		}
	}

	// Next, copy the colour being mapped
	IndexedColour *DestColour = new IndexedColour(*SourceColour);
	if (DestColour == NULL)
		return(NULL);


	// Now ensure our parent/ancestors are mapped, ...
	IndexedColour *SourceParent = SourceColour->FindLinkedParent();
	IndexedColour *DestParent = NULL;
	if (SourceParent != NULL)
	{
		DestParent = MapColour(SourceParent);
		if (DestParent == NULL)
		{
			delete DestColour;
			return(NULL);
		}
	}

	// ... and set the copied colour's parent to the mapped (dest doc) parent, rather than
	// the source doc version of the parent.
	// Note that if this is not a tint/linked colour, this has the side effect of ensuring
	// that Parent is NULL, rather than referencing a parent in a different document
	DestColour->SetLinkedParent(DestParent, DestColour->GetType());
	

	// Finally, map ourselves...
	// Find a blank entry in the mapping tables
	INT32 i = 0;
	while (i < ColourTableSize && SourceColours[i] != NULL)
		i++;

	if (i >= ColourTableSize)	// If no free entries, extend them and get first free entry
		i = ExtendTables();

	if (i < 0)		 			// We failed - no memory for tables
	{
		delete DestColour;
		return(NULL);
	}

	// Check if there is already a matching colour in the dest. document.
	// If there is one, then chuck away DestColour, and use the matching colour instead
	IndexedColour *MatchColour = ExactMatchExists(DestColour);
	if (MatchColour != NULL)	
	{
		delete DestColour;
		DestColour = MatchColour;

		if (AlreadyThere != NULL)	// And return info to indicate that the colour is merged
			*AlreadyThere = TRUE;
	}

	// And finally, write the new entry into the mapping tables
	// (but only if we need to cache the mappings - NOTE that we need to store a
	// mapping (at least to the extent of having a destination part of the mapping)
	// or the new colours won't be added in EndComponentCopy. Unfortunately this
	// means we need a source mapping that isn't NULL or it all falls apart.
	if (SourceIsUnique)
		SourceColours[i] = (IndexedColour *) 1;		// Yeek! Have to stop this being null
	else
		SourceColours[i] = SourceColour;

	DestColours[i]   = DestColour;
	MergeColours[i]  = (MatchColour != NULL);

	return(DestColour);		// And return the result of the mapping operation

	return NULL;
}



/********************************************************************************************

>	ColCompCopyResult CopyColourAcross(DocColour* pDocColour, BOOL SourceIsUnique = FALSE);

	Author:		Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
	Created:	10/9/94

	Inputs:		pDocColour - The colour which resulted from copying across from one document
				to our document.

				SourceIsUnique - FALSE (the default) if you're copying existing document
								 colours around, and therefore could attempt to copy the
								 same colour multiple times.

								 TRUE if you can guarantee that this colour will only be
								 copied once. This is used only for copying library colours
								 into a document in the colour gallery (where it uses a temporary
								 IndexedColour, which causes problems when several different
								 colours accidentally map to the same temporary memory allocation,
								 thus causing rampant incorrect colour merging to occur).
								 ** ONLY USE THIS IF YOU REALLY REALLY BELIEVE YOU MUST - **
								 ** IT SHOULD NOT BE NECESSARY UNDER NORMAL CIRCUMSTANCES **

	Returns:	CCCOPY_FAILED = 0/FALSE	- if it failed, in which case the error has been reported

				CCCOPY_NEWCOLOUR		- if it succeeded by creating a new colour

				CCCOPY_MERGEDCOLOUR		- if it succeeded by merging (using an existing colour)

	Purpose:	If the DocColour references an IndexedColour then a copy of that IxColour is
				made and remembered. The DocColour is then changed to reference the new
				indexed colour. On calling EndComponentCopy, these new IndexedColours will
				be added to the document. If a failure occurs at any stage, you must
				*immediately* undo the entire copy operation, deleting all the nodes
				referencing the new colours we've created, before calling AbortComponentCopy

				Chains of linked/tint IndexedColours are also handled properly.

	Notes:		If this function returns FALSE, you MUST clean up and then call 
				AbortComponentCopy to clean up.

	Errors:		Memory errors are reported immediately
				If StartComponentCopy has not been called, or an internal consistency failure
				occurs (our working array pointer(s) are NULL), an ERROR2 will be reported.

	SeeAlso:	ColourListComponent::StartComponentCopy;
				ColourListComponent::AbortComponentCopy;
				ColourListComponent::EndComponentCopy

********************************************************************************************/

ColCompCopyResult ColourListComponent::CopyColourAcross(DocColour* pDocColour, BOOL SourceIsUnique)
{
	IndexedColour *SourceColour = pDocColour->FindParentIndexedColour(); 

	if (SourceColour == NULL)	// Doesn't reference an IndexedColour, so return success
		return(CCCOPY_MERGEDCOLOUR);

	if (SourceColours == NULL || DestColours == NULL || MergeColours == NULL)
	{
		ERROR2RAW("ColourListComponent::CopyColourAcross called without a prior StartComponentCopy");
		InformError();
		return(CCCOPY_FAILED);
	}

	BOOL WasMerged = FALSE;
	IndexedColour *NewColour = MapColour(SourceColour, &WasMerged, SourceIsUnique);
	if (NewColour == NULL)		// An error (no memory) occurred - abort component copy
		return(CCCOPY_FAILED);

	// Fix the colour to reference the destination copy of the indexed colour
	pDocColour->MakeRefToIndexedColour(NewColour);
	return((WasMerged) ? CCCOPY_MERGEDCOLOUR : CCCOPY_NEWCOLOUR);

	return CCCOPY_FAILED;
}


/********************************************************************************************

>	IndexedColour* ColourListComponent::GetIndexedParentOfColour(DocColour Colour)

	Author:		Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
	Created:	17/5/2000
	Inputs:		Colour - the doccolour that was originally created from an indexed colour
	Outputs:	-
	Returns:	the indexed colour that originally created Colour, if there is one, else NULL
	Purpose:	It is possible for us to create doccolours from indexed colours and then convert
				them so that they are standalone.  This method goes through all the indexed
				colours to try and find out which indexed colour (if any) originally created the input

********************************************************************************************/

IndexedColour* ColourListComponent::GetIndexedParentOfColour(DocColour Colour)
{
	ColourList* pList = GetColourList();
	if (pList == NULL)
		return NULL;

	ColourGeneric ColDef;
	ColourContext *cc = ColourManager::GetColourContext(Colour.GetColourModel());
	ERROR2IF(cc == NULL, NULL,  "Can't find colour context?!");
	DocColour ConvertedDocCol;
	
	IndexedColour* pItem = (IndexedColour*)pList->GetHead();

	// what we have to do is get each indexed colour as a standalone definition then
	// ask it to make a doccolour. If this is the same as our input then we have our match
	while (pItem != NULL)
	{
		// Get the IndexedColour definition as a standalone colour definition
		cc->ConvertColour(pItem, &ColDef);

		// Make the DocColour into a simple standalone "lookalike" of the parent colour
		ConvertedDocCol = DocColour(Colour.GetColourModel(), &ColDef);
		
		// now test to see if its the same, if so we've got what we want
		if (ConvertedDocCol == Colour)
			break;

		pItem = (IndexedColour*)pList->GetNext(pItem);
		
	
	}
	return pItem;
}
