// $Id: basedoc.cpp 1282 2006-06-09 09:46:49Z 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============================ */ // Implementation of BaseDocument class /* */ #include "camtypes.h" //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "camelot.h" //#include "basedoc.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "colcomp.h" //#include "doccomp.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "dumbnode.h" //#include "jason.h" #include "nodedoc.h" #include "progress.h" #include "fontlist.h" //#include "textinfo.h" //#include "mario.h" //#include "resource.h" #include "fontman.h" #include "collist.h" #include "camdoc.h" #include "exphint.h" #include "nodeliveeffect.h" //#include "xpehost.h" //#include "peter.h" //#include "simon.h" #ifdef RALPH #include "ralphcri.h" #endif DECLARE_SOURCE($Revision: 1282 $) CC_IMPLEMENT_DYNAMIC(BaseDocument, ListItem) // Declare smart memory handling in Debug builds #define new CAM_DEBUG_NEW /******************************************************************************************** > BaseDocument::BaseDocument(BOOL fHide = TRUE) Author: Simon_Maneggio (Xara Group Ltd) Created: 20/7/94 Inputs: - Outputs: - Returns: - Purpose: BaseDocument constructor Errors: - SeeAlso: - ********************************************************************************************/ BaseDocument::BaseDocument(BOOL fHide) : IsHidden(fHide), m_pExportHint(NULL), TreeStart(0), DocComponents(0), TagCounter(1) { // Empty. } /******************************************************************************************** > BaseDocument::~BaseDocument() Author: Simon_Maneggio (Xara Group Ltd) Created: 20/7/94 Purpose: The BaseDocument destructor deletes all nodes in the document. It also deletes all the document components. ********************************************************************************************/ BaseDocument::~BaseDocument() { // Destroy the tree if it exists. This routine deletes all nodes to the right of // the StartDocument node. This is done by continually deleting the node to the // right (which shuffles all the others left one) until there are no more nodes. // Then the StartDocument node itself is deleted. if (TreeStart != NULL) { for (Node* pn = TreeStart->FindNext(); pn != NULL; pn = TreeStart->FindNext()) { // Delete the node's children then delete the node. The TreeStart // variable will be updated to point to the new first node. pn->CascadeDelete(); delete pn; } // Tree has only one node left - waste it. delete TreeStart; TreeStart = NULL; } // The SelRange might still contain cached indexed colours. We must delete these // before destroying the DocComponents. SelRange* Sel = GetApplication()->FindSelection(); if (Sel) Sel->AttrsHaveChanged(); // Destroy doc components (colours, etc) // (this must be left until after all possible things in the document that could // contain references to components (such as IndexedColours) have been deleted) DestroyDocComponents(); if (m_pExportHint) { delete m_pExportHint; m_pExportHint = NULL; } } /******************************************************************************************** > void BaseDocument::DestroyDocComponents(void) Author: Jason_Williams (Xara Group Ltd) Created: 25/4/95 Purpose: Deletes all DocComponents and related junk from this document Used by the destructor, and also by the InternalClipboard document when it wipes the clipboard. SeeAlso: BaseDocument::InitDocComponents ********************************************************************************************/ void BaseDocument::DestroyDocComponents(void) { // And delete all the document components if (DocComponents != NULL) { DocComponents->DeleteAll(); delete DocComponents; DocComponents = NULL; } } /******************************************************************************************** > BOOL BaseDocument::Init() Author: Simon_Maneggio (Xara Group Ltd) Created: 20/7/94 Purpose: Creates StartDocument, NodeDocument, and EndDocument nodes. Initialises the doc components. ********************************************************************************************/ BOOL BaseDocument::Init() { NodeDocument *Doc; EndDocument *End; // Get a new StartDocument node. TreeStart = new StartDocument; if (TreeStart == NULL) goto NoMemory; // Add a NodeDocument Doc = new NodeDocument(TreeStart, NEXT); if (Doc == NULL) goto NoMemory; // Tell the NodeDocument which document it is attached to. Doc->SetParentDoc(this); // Join a new EndDocument node after it in the tree. End = new EndDocument(Doc, NEXT); if (End == NULL) goto NoMemory; if (!InitDocComponents()) goto NoMemory; // We don't really mind if this fails but check it anyway m_pExportHint = new ExportHint; if (m_pExportHint == NULL) goto NoMemory; // All is well return TRUE; NoMemory: // Failed to initialise due to running out of memory. if (TreeStart != NULL) { TreeStart->CascadeDelete(); delete TreeStart; TreeStart = NULL; } return FALSE; } /******************************************************************************************** > BOOL BaseDocument::InitDocComponents(void) Author: Jason_Williams (Xara Group Ltd) Created: 25/4/95 Returns: TRUE if it succeeds Purpose: Creates and initialises all doc components This is a subroutine called by Init(), and is also used by the InternalClipboard document when clearing the clipboard in order to wipe all contents of the document. SeeAlso: BaseDocument::DestroyDocComponents ********************************************************************************************/ BOOL BaseDocument::InitDocComponents(void) { // Get a new set of document components for this document... DocComponents = new List; if (DocComponents == NULL) return(FALSE); // Get each of the registered document components to add themselves to the document. if (!GetApplication()->ApplyDocComponents(this)) return(FALSE); return(TRUE); } /*********************************************************************************************** > TAG BaseDocument::NewTag() Author: Tim_Browse (Xara Group Ltd) Created: 19/5/93 Purpose: Returns a new unique TAG for this Document. ***********************************************************************************************/ TAG BaseDocument::NewTag() { // Increment and check for loop around. if (TagCounter == TAG_LAST_VALID) TagCounter = 1; // NB 0 is not used (not sure why - Tim). else TagCounter++; // Return a unique tag return TagCounter; } /******************************************************************************************** > void BaseDocument::IncNodeCount() Author: Tim_Browse (Xara Group Ltd) Created: 15/02/95 Purpose: Adds one to the NodesInTree counter of this Document object. Called by the constructors of class Node. SeeAlso: BaseDocument::DecCurrentNodeCount; BaseDocument::NodesInDocument ********************************************************************************************/ void BaseDocument::IncNodeCount() { NodesInTree++; } /******************************************************************************************** > void BaseDocument::DecNodeCount() Author: Justin_Flude (Xara Group Ltd) Created: 30/11/93 Purpose: Decrements the node counter in this Document. Called by the destructor of class Node. SeeAlso: BaseDocument::IncNodeCount; BaseDocument::NodesInDocument ********************************************************************************************/ void BaseDocument::DecNodeCount() { NodesInTree--; } /******************************************************************************************** > INT32 BaseDocument::NodesInDocument() const Author: Justin_Flude (Xara Group Ltd) Created: 30/11/93 Returns: The number of nodes in this Document's tree. Purpose: Returns the nodes in the document's tree, ho hum. SeeAlso: BaseDocument::IncNodeCount; BaseDocument::DecNodeCount ********************************************************************************************/ INT32 BaseDocument::NodesInDocument() const { return NodesInTree; } /*********************************************************************************************** > Node* BaseDocument::GetFirstNode() const Author: Tim_Browse (Xara Group Ltd) Created: 19/5/93 Inputs: - Outputs: - Returns: First node in the tree. Purpose: Get the first node in the document tree - this will always be a StartDocument node. (* Moved from Document to BaseDocument by SimonM *) Errors: None. ***********************************************************************************************/ Node* BaseDocument::GetFirstNode() const { return TreeStart; } /******************************************************************************************** > void BaseDocument::AddDocComponent(DocComponent *pComponent) Author: Tim_Browse (Xara Group Ltd) Created: 02/08/94 Inputs: pComponent - the document component to add. Purpose: Add the given document component to the document - no check is made to see if such a component is already in the document - the caller should ensure that they do not overwrite the existing component. Errors: ENSURE of no document component list exists in the document. SeeAlso: BaseDocument::GetDocComponent; BaseDocument::GetDocComponentKindOf ********************************************************************************************/ void BaseDocument::AddDocComponent(DocComponent *pComponent) { // Basic sanity/safety checks. ENSURE(DocComponents != NULL, "No document component list in the document!"); if (DocComponents == NULL) return; // Just add the component to the document's list. DocComponents->AddTail(pComponent); } /******************************************************************************************** > DocComponent *BaseDocument::GetDocComponent(CCRuntimeClass *pClass) Author: Tim_Browse (Xara Group Ltd) Created: 02/08/94 Inputs: pClass - the class of component to look for. Returns: A pointer to the required component, or NULL if no match was found. Purpose: Find a document component of a specific type in this document. SeeAlso: BaseDocument::GetDocComponentKindOf; DocComponent ********************************************************************************************/ DocComponent *BaseDocument::GetDocComponent(CCRuntimeClass *pClass) { DocComponent *pItem = (DocComponent *) DocComponents->GetHead(); while (pItem != NULL) { // Is this an exact match to the given runtime class? if (pItem->GetRuntimeClass() == pClass) // Yes - return to caller. return pItem; // Try the next component pItem = (DocComponent *) DocComponents->GetNext(pItem); } // Didn't find the component - report this to caller return NULL; } /******************************************************************************************** > DocComponent *BaseDocument::GetDocComponentKindOf(CCRuntimeClass *pClass) Author: Tim_Browse (Xara Group Ltd) Created: 02/08/94 Inputs: pClass - the base class of the component to look for. Returns: A pointer to the required component, or NULL if no match was found. Purpose: Find a kind of document component of in this document - it must be derived from the class described by pClass. SeeAlso: BaseDocument::GetDocComponent; DocComponent ********************************************************************************************/ DocComponent *BaseDocument::GetDocComponentKindOf(CCRuntimeClass *pClass) { DocComponent *pItem = (DocComponent *) DocComponents->GetHead(); while (pItem != NULL) { // Is this derived from the base class specified? if (pItem->IsKindOf(pClass)) // Yes - return to caller. return pItem; // Try the next component pItem = (DocComponent *) DocComponents->GetNext(pItem); } // Didn't find the component - report this to caller return NULL; } /******************************************************************************************** > DocComponent *BaseDocument::EnumerateDocComponents(DocComponent *pContext) Author: Tim_Browse (Xara Group Ltd) Created: 02/08/94 Inputs: pContext: NULL => Get the first document component non-NULL => Get the next document component after the one pointed to by pContext. Returns: Pointer to the required document component. Purpose: Allow the caller to examine/use all the document components attached to this document.. pContext should be NULL for the first call, which will return the first document component. After that, the returned pointer should be passed back in to this function, which will return the next one, and so on. For example: MonoOn DocComponent *pDocComp = NULL; do { pDocComp = pDoc->EnumerateDocComponents(pDocComp); // Do something groovy with pDocComp... } while (pDocComp != NULL); MonoOff SeeAlso: DocComponent ********************************************************************************************/ DocComponent *BaseDocument::EnumerateDocComponents(DocComponent *pContext) { if (pContext == NULL) { // Return the first item in the list... return (DocComponent *) (DocComponents->GetHead()); } else { // Return the next document component... return (DocComponent *) (DocComponents->GetNext(pContext)); } } /******************************************************************************************** > virtual BOOL BaseDocument::StartComponentCopy() Author: Simon_Maneggio (Xara Group Ltd) Created: 16/8/94 Inputs: - Outputs: - Returns: FALSE if a call to DocComponent::StartComponentCopy fails. In this case AbortComponentCopy gets called. Purpose: This function traverses the documents list of DocComponents and calls the virtual StartComponentCopy method on them. It calls AbortComponent copy on all DocComponents if we fail. Errors: - SeeAlso: DocComponent::StartComponentCopy ********************************************************************************************/ BOOL BaseDocument::StartComponentCopy() { DocComponent* Current = (DocComponent*) DocComponents->GetHead(); DocComponent* Next; while (Current != NULL) { Next = (DocComponent*) DocComponents->GetNext(Current); if (!Current->StartComponentCopy()) { AbortComponentCopy(); return FALSE; } Current = Next; } return TRUE; } /******************************************************************************************** > virtual BOOL BaseDocument::EndComponentCopy() Author: Simon_Maneggio (Xara Group Ltd) Created: 16/8/94 Inputs: - Outputs: - Returns: FALSE if a call to DocComponent::EndComponentCopy fails. In this situation Abort component copy is called. Purpose: This function traverses the documents list of DocComponents and calls the virtual EndComponentCopy method on them Errors: - SeeAlso: DocComponent::EndComponentCopy ********************************************************************************************/ BOOL BaseDocument::EndComponentCopy() { DocComponent* Current = (DocComponent*) DocComponents->GetHead(); DocComponent* Next; while (Current != NULL) { Next = (DocComponent*) DocComponents->GetNext(Current); if (!Current->EndComponentCopy()) { AbortComponentCopy(); return FALSE; } Current = Next; } return TRUE; } /******************************************************************************************** > virtual void BaseDocument::AbortComponentCopy() Author: Simon_Maneggio (Xara Group Ltd) Created: 16/8/94 Inputs: - Outputs: - Returns: - Purpose: This function traverses the documents list of DocComponents and calls the virtual AbortComponentCopy method on them Errors: - SeeAlso: DocComponent::AbortComponentCopy ********************************************************************************************/ void BaseDocument::AbortComponentCopy() { DocComponent* Current = (DocComponent*) DocComponents->GetHead(); DocComponent* Next; while (Current != NULL) { Next = (DocComponent*) DocComponents->GetNext(Current); Current->AbortComponentCopy(); Current = Next; } } /******************************************************************************************** > ColourList *BaseDocument::GetIndexedColours(void) Author: Jason_Williams (Xara Group Ltd) Created: 05/05/94 (Moved here from NodeDocument 1/8/94) Inputs: - Outputs: - Returns: A pointer to this documents list of IndexedColours Purpose: Returns a pointer to a list of the IndexedColours available to the user within this document. Scope: Private (intended only for colour manager to access) Errors: - SeeAlso: class IndexedColour; class ColourList ********************************************************************************************/ ColourList *BaseDocument::GetIndexedColours(void) { // Get the colour list component ColourListComponent *pComponent = (ColourListComponent *) GetDocComponent(CC_RUNTIME_CLASS(ColourListComponent)); if(pComponent == NULL) return NULL; // Extract the colour list return pComponent->GetColourList(); } /******************************************************************************************** > ColourContextArray *BaseDocument::GetDefaultColourContexts(void) Author: Jason_Williams (Xara Group Ltd) Created: 18/04/94 Inputs: - Outputs: - Returns: A pointer to this documents array of default colour contexts. Purpose: Gives access to the Documents array of default colour contexts This is used internally by the DocColour system, and I shouldn't think it will be of much interest to anyone else. Errors: - SeeAlso: ColourContext ********************************************************************************************/ ColourContextArray *BaseDocument::GetDefaultColourContexts(void) { return(&DefaultColourContexts); } /******************************************************************************************** > BOOL BaseDocument::CheckReferences() Author: Phil_Martin (Xara Group Ltd) Created: 31/01/2005 Inputs: - Outputs: - Returns: TRUE/FALSE for Success/Failure Purpose: Checks for references to resources outside the document that may be dangling because the resources are not present. Errors: - SeeAlso: - ********************************************************************************************/ BOOL BaseDocument::CheckReferences() { // URGH! This should be implemented in Document, not BaseDocument! CCamDoc* pOilDoc = NULL; if (IS_KIND_OF(Document)) pOilDoc = ((Document*) this)->GetOilDoc(); if (pOilDoc && pOilDoc->IsVisible()) { // We don't want to show the user a sequence of boxes so collapse all reference // checks into a single warning... // (Argh but it's too much trouble at the mo...) PORTNOTETRACE("text","BaseDocument::CheckReferences - removed CheckFontSubstitution call"); #ifndef EXCLUDE_FROM_XARALX BOOL bFontsOK = CheckFontSubstitution(); #endif BOOL bFontsOK = true; BOOL bEffectsOK = CheckEffects(); #ifndef EXCLUDE_FROM_XARALX BOOL bFontsOK = CheckFontSubstitution(FALSE); BOOL bEffectsOK = CheckEffects(FALSE); if (!bFontsOK || !bEffectsOK) { ErrorInfo warning; String_256 strWarning; strWarning.MakeMsg(_R(IDS_MISSINGREFERENCES), strFontsWarning, strEffectsWarning); warning.ErrorMsg = strWarning; warning.Title = String(_R(IDS_MISSINGREFS_TITLE)); warning.Button[0] = _R(IDB_CONTINUE); InformWarning(warning); } #endif return (bFontsOK && bEffectsOK); } return FALSE; } /******************************************************************************************** > BOOL BaseDocument::CheckFontSubstitution() Author: Mark_Neves (Xara Group Ltd) Created: 31/7/96 Inputs: - Outputs: - Returns: TRUE/FALSE for Success/Failure Purpose: Checks for substituted fonts, and if it finds any, in warns the user. (This code has been separated from PostImport() so it can be called independantly) Errors: - SeeAlso: - ********************************************************************************************/ BOOL BaseDocument::CheckFontSubstitution() { // check whether any fonts have been substituted BOOL FontSubstitution = FALSE; FontList DocFonts; DocFonts.Build((Document*)this); FontListItem* FontItem = DocFonts.GetFirstItem(); if (FontItem!=NULL) { // fill up the list while (FontItem) { // get the name String_64 Name = FontItem->GetFontName(); FontClass Class = FontItem->GetFontClass(); if (FONTMANAGER->IsFontReplaced(&Name, Class)) { FontSubstitution=TRUE; break; } FontItem = DocFonts.GetNextItem(FontItem); } } #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX) if (FontSubstitution) { #if (_OLE_VER >= 0x200) // Only warn about this if the document is visible to the user. CCamDoc* pOilDoc = 0; if (IS_KIND_OF(Document)) pOilDoc = ((Document*) this)->GetOilDoc(); if (pOilDoc && pOilDoc->IsVisible()) #endif // Inform the user that some fonts are not installed Operation::SetQuickRender(TRUE); // Prevent cacheing while this warning is on screen InformWarning(_R(IDS_FONTSSUBSTITUTED), _R(IDS_CONTINUE)); Operation::SetQuickRender(FALSE); } #endif return TRUE; } /******************************************************************************************** > BOOL BaseDocument::CheckEffects() Author: Phil_Martin (Xara Group Ltd) Created: 31/01/2005 Inputs: - Outputs: - Returns: TRUE/FALSE for Success/Failure Purpose: Checks for missing effects, and warn the user. Errors: - SeeAlso: - ********************************************************************************************/ BOOL BaseDocument::CheckEffects() { ListRange* pEffectList = GetEffectsList(500000); // Arbitrary large number BOOL bFound = TRUE; if (pEffectList) { Node* pNode = pEffectList->FindFirst(); while (pNode) { if (pNode->IsBitmapEffect()) { NodeBitmapEffect* pEffect = (NodeBitmapEffect*)pNode; if (!pEffect->IsLockedEffect()) { PORTNOTE("other","Removed XPEHost usage") #ifndef EXCLUDE_FROM_XARALX // Live effects need to regenerate their bitmaps so we must // test whether the handler is present and warn the user if not String_64 strDisplayName; bFound = XPEHost::GetEffectDetails(pEffect->GetPostProcessorID(), &strDisplayName); if (!bFound) { break; } #endif } } pNode = pEffectList->FindNext(pNode); } delete pEffectList; } if (!bFound) { Operation::SetQuickRender(TRUE); // Prevent cacheing while this warning is on screen InformWarning(_R(IDS_FINFO_MISSINGEFFECTS), _R(IDS_CONTINUE)); Operation::SetQuickRender(FALSE); } return TRUE; } /******************************************************************************************* > ListRange* BaseDocument::GetEffectsList(UINT32 iMaxItems) Author: Phil_Martin (Xara Group Ltd) Created: 31/01/2005 Inputs: - Outputs: - Returns: True if completed ok, False otherwise. Purpose: Updates the effects list showing referred and missing effects Errors: - SeeAlso: SetDocInfo; FontDropDown; DocumentFontDropDown; *******************************************************************************************/ ListRange* BaseDocument::GetEffectsList(UINT32 iMaxItems) { // Make a list of all unique effects used in the doc // Add each list item to the listbox, marking it if the referred effect can not // be found in the installed effect list ListRange* pEffectList = new ListRange(); Node* pNode = GetFirstNode(); UINT32 i = 0; while (pNode && iIsBitmapEffect()) { NodeBitmapEffect* pEffect = (NodeBitmapEffect*)pNode; // Search for this type of effect in the list already Node* pListNode = pEffectList->FindFirst(); while (pListNode) { if (((NodeBitmapEffect*)pListNode)->GetPostProcessorID() == pEffect->GetPostProcessorID()) break; pListNode = pEffectList->FindNext(pListNode); } // If this effect type is not already in the list, add it if (pListNode==NULL) { pEffectList->AddNode(pNode); i++; } } pNode = pNode->FindNextDepthFirst(NULL); } return pEffectList; } /******************************************************************************************** > void BaseDocument::PostImport() Author: Peter_Arnold (Xara Group Ltd) Created: 04/04/95 Inputs: - Outputs: - Returns: TRUE/FALSE for Success/Failure (you what? Surely some mistake? Sack the programmer) Purpose: Scans the entire tree, calling all nodes PostImport function. If any of functions returns FALSE the error is reported and the scan continues. Errors: - SeeAlso: - ********************************************************************************************/ void BaseDocument::PostImport() { #ifdef RALPH // We don't want to be rendering at the same time as doing this, because we get // blobby text problems - fun, but bad ! RalphCriticalSection RalphCS; #endif BeginSlowJob(); // Get a pointer to the StartDocument node Node* pStartNode = GetFirstNode(); ERROR3IF(pStartNode == NULL, "(BaseDocument::PostImport) TreeStart was NULL"); // Get a pointer to the NodeDocument node if (pStartNode != NULL) { pStartNode = pStartNode->FindNext(); ERROR3IF(pStartNode == NULL, "(BaseDocument::PostImport) No NodeDocument after StartDocument"); } // Scan through the tree, calling all PostImport functions if (pStartNode != NULL) { Node* pCurrentNode = pStartNode->FindFirstDepthFirst(); while (pCurrentNode != NULL) { if (!pCurrentNode->PostImport()) { InformError(); } pCurrentNode = pCurrentNode->FindNextDepthFirst(pStartNode); } } // check whether any fonts have been substituted, and warn the user if they have // CheckFontSubstitution(); CheckReferences(); EndSlowJob(); }