document.cpp

Go to the documentation of this file.
00001 // $Id: document.cpp 1668 2006-08-04 11:45:17Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 #include "camtypes.h"
00100 
00101 #include <fstream>
00102 //#include <strstream> // this seems to be deprecated
00103 #include <ctype.h>
00104 #include <string>   
00105 #include <stdlib.h>     // for rand() fn
00106 
00107 #include "camdoc.h"
00108 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "docmsgs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 
00111 #include "dumbnode.h"
00112 #include "noderect.h"
00113 //#include "ensure.h"  - in camtypes.h [AUTOMATICALLY REMOVED]
00114 #include "lineattr.h"        
00115 #include "colcontx.h"
00116 //#include "doccolor.h"
00117 //#include "colourix.h"
00118 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "readeps.h"
00120 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "csrstack.h"
00124 #include "grid.h"
00125 #include "nodedoc.h"
00126 #include "chapter.h"
00127 #include "page.h"
00128 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00129 #include "wrkrect.h"
00130 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00131 //#include "msg.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00132 #include "sprdmsg.h"
00133 #include "layer.h"
00134 #include "insertnd.h"
00135 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00136 #include "camview.h"
00137 //#include "native.h"           // The new designed native filter, used for v2
00138 #include "nativeps.h"       // The old style EPS native filter, used in v1.1
00139 #include "saveeps.h"
00140 #include "zoomops.h"
00141 #include "qualops.h"
00142 #include "ai_eps.h"
00143 #include "ai_epsrr.h"
00144 #include "fontlist.h"
00145 #include "fontman.h"
00146 #include "progress.h"
00147 #include "bmpcomp.h"
00148 #include "ralphdoc.h"
00149 #include "camelot.h"        // For SafeRender Critical section stuff
00150 //#include "clipint.h"
00151 #include "nodedoc.h"
00152 #include "ngsentry.h"
00153 #include "opnudge.h"
00154 #include "ophist.h"
00155 #include "cutop.h"
00156 
00157 //#include "ralphvw.h"
00158 #include "vstate.h"
00159 
00160 DECLARE_SOURCE("$Revision: 1668 $");
00161 
00162 CC_IMPLEMENT_DYNAMIC(Document, BaseDocument)
00163 CC_IMPLEMENT_DYNAMIC(DocChangingMsg, Msg)
00164 CC_IMPLEMENT_DYNAMIC(SpreadMsg, Msg)
00165 CC_IMPLEMENT_DYNAMIC(TranspModeMsg, Msg)
00166 CC_IMPLEMENT_DYNAMIC(SafeRenderPointer, CCObject)
00167 
00168 // Declare smart memory handling in Debug builds
00169 #define new CAM_DEBUG_NEW
00170 
00171 const MILLIPOINT PageWidth  = ( 8 * 72000);
00172 const MILLIPOINT PageHeight = (11 * 72000);
00173 
00174 // Default page size/position.
00175 const MILLIPOINT Gap = 72000L;
00176 const MILLIPOINT PasteBoardWidth  = PageWidth + (Gap * 2);
00177 const MILLIPOINT PasteBoardHeight = PageHeight + (Gap * 2);
00178 const MILLIPOINT DefBleedSize = 72000L/4;
00179 
00180 
00181 Document* Document::Current  = NULL;
00182 Document* Document::Selected = NULL;
00183 
00184 Spread*   Document::pGlobalSelSpread = NULL;
00185 
00186 BOOL Document::fRestoreViewOnImport = TRUE;
00187 
00188 
00189 static String_256 ClipboardNameText(TEXT("Clipboard"));
00190 
00191 // the default nudge size for our documents ....
00192 // NOTE:  if you change this, you should also update the hard-coded value within:
00193 // GeneralRecordHandler::HandleTagNudeSizeRecord ().  I could move this to the .h; but I can't
00194 // be bothered ....
00195 const UINT32 DEFAULT_NUDGE_SIZE = 2835;
00196 
00197 
00198 
00199 /***********************************************************************************************
00200 
00201 >   Document::Document(BOOL IsAHiddenDoc = FALSE)
00202 
00203     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00204     Created:    19/5/93
00205     Inputs:     IsAHiddenDoc - FALSE for a normal document (see below)
00206                                 TRUE for a hidden document (including clipboards, etc)
00207 
00208     Purpose:    Constructor. Initialises the link to the OIL document.
00209 
00210     Notes:      You MUST call Document::Init after Creation of the document, to fill in
00211                 the defaults and build the document tree root.
00212 
00213                 HIDDEN DOCUMENTS
00214                 A hidden document is one which is not shown to the user in any UI.
00215                 Hidden docs are used mainly for clipboard (and OLE) data transfer operations.
00216 
00217                 Note that if you pass in (pCCamDoc = NULL) then the document is forced to be hidden.
00218                 SeeAlso IsAHiddenDoc() and IsNotAHiddenDoc() in document.h
00219 
00220                 The InternalClipboard is now based upon Document. It creates a Hidden Document.
00221                 Generally nobody should care about this, but some bits of code might have to be
00222                 careful of the differences. Use IsAClipboard() to check if the doc is really a
00223                 clipboard. Note also that Clipboard documents do not broadcast DocChangingMsgs.
00224 
00225     Errors:     None.
00226     SeeAlso:    Document::Init; InternalClipboard; BaseDocument
00227 
00228 ***********************************************************************************************/
00229 
00230 Document::Document(BOOL bIsAHiddenDoc)
00231   : BaseDocument(bIsAHiddenDoc),
00232     OilDoc(0)
00233 {
00234     // NB. Make sure all the Document stuff is set up before calling routines which
00235     // might interrogate the Document object.
00236     
00237     // Set the default state of the flags.
00238     DocFlags.LayerMultilayer = FALSE;
00239     DocFlags.LayerAllVisible = FALSE;
00240     DocFlags.SaveWithUndo = TRUE;
00241 
00242     // Set the times
00243     CreationTime = ::time(NULL);
00244     LastSaveTime = 0;
00245 
00246     // Set up default bleed offset
00247     BleedOffset = DefBleedSize;
00248 
00249     // Set up our array of default colour contexts by copying the 'global' array
00250     ColourContext::GetGlobalDefaults( &DefaultColourContexts );
00251 
00252     // Add this document to the list of all documents in Camelot
00253 #ifdef RALPH
00254     Camelot.Documents.AddHead(this);
00255 #else
00256     if (IsNotAHiddenDoc())
00257     {
00258         Camelot.Documents.AddHead(this);
00259     }
00260 #endif
00261 
00262     // Set this document to be the current one
00263     this->SetCurrent();
00264 
00265     NodesInTree = 0;       
00266                                  
00267     // Initialise pointers to sensible values (they are set up in the Init() function)
00268     OpHistory           = 0;
00269     AttributeMgr        = 0;
00270     m_pSetSentinel      = 0;
00271     pDocUnitList        = 0;
00272     pSelSpread          = 0;
00273 
00274     IsARalph = FALSE;
00275     pRalphDocument =NULL;
00276     Viewmode = DOCUMENT_VIEW;
00277 
00278     // Always keep this flag TRUE except when Loading New Files in
00279     DocIsImporting = TRUE;
00280 
00281     // Always keep this False unless loading a template document
00282     DocTemplateLoading = FALSE;
00283 
00284     // Make sure that the loaded as old version file is set to a known state
00285     LoadedAsVersion1File = FALSE;
00286 
00287     m_docNudge = DEFAULT_NUDGE_SIZE;
00288     SetBitmapSmoothing(TRUE);
00289     m_DuplicationOffset = DocCoord(OpDuplicate::DuplicatePlacementX, OpDuplicate::DuplicatePlacementY);
00290 
00291     // Document is not yet "born and stable".
00292     m_fStable = FALSE;
00293 }
00294 
00295 
00296 
00297 /********************************************************************************************
00298 
00299 >   BOOL Document::Init(CCamDoc* pOilDoc)
00300 
00301     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00302     Created:    20/7/93
00303     Inputs:     pOilDoc     ---     the CCamDoc to attach this Document too
00304     Returns:    TRUE if the document initialised ok, FALSE otherwise.
00305     Purpose:    Sets up the document tree.  At the moment it fills it with test data
00306                 (paths etc) but in future only the initial tree nodes will be set up.
00307                 When the document has been completely initialised, it becomes the
00308                 selected and current document: DocChangingMsg message broadcasts will
00309                 occur (in the order BORN, CURRENT, SELECTED).
00310 
00311     Notes:      This now also sets up the default list of indexed (named) colours which
00312                 the user can base their document upon [in the BaseDocument Init method].
00313                 These should be set up from a default document (or whatever) in future.
00314 
00315     Errors:     Out of memory.
00316     SeeAlso:    ReadEPSData; Document::Document;
00317                 Document::SetSelectedViewAndSpread; Document::SetCurrent
00318 
00319 ********************************************************************************************/
00320 
00321 BOOL Document::Init(CCamDoc* pOilDoc)
00322 {
00323 // Ralph has a NULL oildoc...
00324 #ifndef RALPH
00325     ERROR2IF(OilDoc, FALSE, "Document already attached to a CCamDoc in Document::Init");
00326 #endif
00327     OilDoc = pOilDoc;
00328 
00329     NodeDocument* Doc;
00330     EndDocument* End;
00331 
00332     // Make this the current document - NOTE! no broadcast as of 22/7/94
00333     SetCurrent();
00334     
00335     // Set the busy cursor . . .
00336     BeginSlowJob(-1, FALSE);
00337 
00338     // First, call the base class Init method to set up for us.
00339     // This creates the StartDocument, NodeDocument, & EndDocument, and sets up
00340     // a default colour list and other doc components.
00341     if (!BaseDocument::Init()) return InitFailed();
00342 
00343     // Check that the document is OK
00344     ERROR3IF(GetFirstNode() == NULL,"StartDoc not found"); 
00345     Doc = (NodeDocument*)GetFirstNode()->FindNext(); 
00346     ERROR3IF(Doc == NULL, "NodeDocument not found"); 
00347     End = (EndDocument*)Doc->FindNext(); 
00348     ERROR3IF(End == NULL, "EndDocument not found"); 
00349 
00350     // Make the doc unit list
00351     pDocUnitList = new DocUnitList;
00352     if (pDocUnitList == NULL || !pDocUnitList->MakeDefaultUnits())
00353         return(InitFailed());
00354 
00355     // Create the Operation history for the document                              
00356     OpHistory = new OperationHistory;
00357     if (OpHistory == NULL)
00358         return(InitFailed());
00359 
00360     // Create the attribute manager for the document 
00361     AttributeMgr = new AttributeManager; 
00362     if (AttributeMgr == NULL || !AttributeMgr->InitInstance())
00363         return(InitFailed());
00364 
00365     // Build the basic tree structure (Chapter, spread, layer)
00366     if (!InitTree(Doc))
00367         return(InitFailed());
00368 
00369     if (IsNotAHiddenDoc())
00370     {
00371         // Broadcast a message to all that there's a new document on the block . . .
00372         BROADCAST_TO_ALL(DocChangingMsg(this, DocChangingMsg::BORN));
00373     }
00374     
00375     // Add the default attributes as Nodes at the start of the tree
00376     // The clipboard document does not need default attributes, as things copied into it
00377     // are always kept attribute complete. But now that we're importing into the clipboard,
00378     // it is a very good idea to have safe defaults lying about.
00379     InitDefaultAttributeNodes(); 
00380 
00381     // Take the hourglass off
00382     EndSlowJob();
00383     
00384     return(TRUE);
00385 }
00386 
00387 
00388 
00389 /********************************************************************************************
00390 
00391 >   BOOL Document::InitTree(NodeDocument *RootNode)
00392 
00393     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00394     Created:    23/4/95
00395 
00396     Inputs:     RootNode - points at the basic NodeDocument from which the main documet
00397                 tree hangs.
00398 
00399     Returns:    TRUE if it succeeds, FALSE if it failed (in which case you should
00400                 call InitFailed() and possibly InformError())
00401 
00402     Purpose:    Called by Document::Init to initialise the document tree structure.
00403                 
00404                 Mainly intended for use by the internal clipboard in order to delete
00405                 and recreate the standard tree whenever it is wiped - I've done this
00406                 here dso that any chnages to the normal document layout will also affect
00407                 the clipboard document in an appropriate manner.
00408 
00409     Errors:     Lack of memory might make 'new' fail
00410 
00411     SeeAlso:    Document::Init
00412 
00413 ********************************************************************************************/
00414 
00415 BOOL Document::InitTree(NodeDocument* pRootNode)
00416 {
00417     if (pRootNode == NULL || !pRootNode->IsNodeDocument())
00418     {
00419         ERROR3("This doc's NodeDocument is NULL or isn't really a NodeDocument");
00420         return(FALSE);
00421     }
00422 
00423     // Temporary bodge to construct example document tree for Target 1.     
00424     Chapter* pChapter = new Chapter(pRootNode, LASTCHILD);
00425     if (pChapter == 0) return FALSE;
00426 
00427     // Create the sentinel node for all object names within the chapter, and a
00428     // child NodeBarProperty.
00429     m_pSetSentinel = new NodeSetSentinel(pChapter, FIRSTCHILD);
00430     if (m_pSetSentinel == 0) return FALSE;
00431     NodeBarProperty* pbp = new NodeBarProperty(m_pSetSentinel, LASTCHILD);
00432     if (pbp == 0) return FALSE;
00433 
00434     // Create a rectangle for the pasteboard
00435     DocRect PasteRect(MinDocCoord + 0x10000,
00436                       MaxDocCoord - 0x10000 - 1 * PasteBoardHeight,
00437                       MinDocCoord + 0x10000 + 2 * PasteBoardWidth,
00438                       MaxDocCoord - 0x10000);
00439 
00440     // Create the spread
00441     Spread *pSpread = new Spread(pChapter, FIRSTCHILD, PasteRect);
00442     if (pSpread == NULL) return FALSE;
00443     
00444     // Create the default page and grid (JustinF says: even if we are a hidden document)
00445     if (!pSpread->CreateDefaultPageAndGrid(TRUE)) return FALSE;
00446 
00447     // Create the Insertion node which must always live as a last child of the selected
00448     // spreads active layer. The Insertion node holds a pointer to this document so that
00449     // if for whatever reason the InsertionNode is destroyed (eg. Delete layer) then 
00450     // we can Inform this document and it can NULLIFY the InsertPos pointer.
00451     InsertPos = new InsertionNode(this);
00452     if (InsertPos == NULL) return FALSE;
00453     InsertPos->AttachNode(pSpread, LASTCHILD);
00454 
00455     return TRUE;
00456 }
00457 
00458 
00459 
00460 /********************************************************************************************
00461 
00462 >   BOOL Document::InitDefaultAttributeNodes()
00463 
00464     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00465     Created:    22/06/94
00466     Inputs:     -
00467     Outputs:    -
00468     Returns:    TRUE if the default attributes have been added to the tree OK
00469                 FALSE if we run out of memory.
00470                 
00471     Purpose:    This function adds the document's default attributes as nodes at the start
00472                 of the tree (i.e. as first children of the NodeDocument).
00473 
00474                 The Attribute optimisation routines will not work if the document does
00475                 not contain the default attributes.
00476 
00477     Note:       This function must be called after the initial document structure has
00478                 been set up and all default attributes have been registered.
00479 
00480 
00481     Errors:     The Out Of Memory Error is set if we run out of memory, FALSE is returned 
00482                 in this situation.
00483                  
00484 
00485 ********************************************************************************************/
00486 
00487 BOOL Document::InitDefaultAttributeNodes()
00488 {
00489     ENSURE(AttributeMgr != NULL, "Attribute Manager pointer is NULL"); 
00490 
00491     // Find out the number of default attributes
00492     UINT32 NumDefaultAttribs = AttributeMgr->GetNumAttributes();
00493     ENSURE(NumDefaultAttribs != 0, "The document has no default attributes"); 
00494     
00495     AttributeEntry* DefaultAttribs = AttributeMgr->GetDefaultAttributes();
00496     
00497     if (DefaultAttribs == NULL)
00498         return FALSE;
00499     
00500     // ----------------------------------------------------------------------------------------
00501     // Try and find the NodeDocument node - to which the attributes will be added
00502 
00503     Node* TreeRoot; 
00504 
00505     ENSURE(TreeStart != NULL, "The initial tree structure has not been initialised"); 
00506 
00507     TreeRoot = TreeStart->FindNext(); 
00508 
00509     ENSURE(TreeRoot != NULL, "Can't find NodeDocument"); 
00510     ENSURE(TreeRoot->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeDocument), "Alien tree structure"); 
00511 
00512     // ----------------------------------------------------------------------------------------
00513     // Create a NodeAttribute for each of the default attributes and add them into the
00514     // tree as first children of the NodeDocument.
00515 
00516     for(UINT32 i=0; i<NumDefaultAttribs; i++)
00517     {
00518         ENSURE(DefaultAttribs[i].pAttr != NULL, "Default attribute is NULL"); 
00519         
00520         Node* NodeAttr = DefaultAttribs[i].pAttr->MakeNode();
00521 
00522         if (NodeAttr != NULL)
00523         {
00524             // Add the Attribute as a first child of the NodeDocument.  Note that we suppress
00525             // the transparency check for default attributes.
00526             NodeAttr->AttachNode(TreeRoot, FIRSTCHILD, FALSE);
00527 
00528             NodeAttribute* pNa = (NodeAttribute*)NodeAttr;
00529             if(pNa->IsLinkedToNodeGeometry())
00530             {
00531                 pNa->NewlyCreatedDefaultAttr((NodeDocument*)TreeRoot);
00532             }
00533         } 
00534     }
00535 
00536     // ----------------------------------------------------------------------------------------
00537 
00538     // Default attribute array no longer required so we can safely delete it 
00539     CCFree(DefaultAttribs);
00540     return TRUE;
00541 }
00542 
00543 
00544 
00545 /********************************************************************************************
00546 
00547 >   BOOL Document::ReInit()
00548 
00549     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00550     Created:    16/4/96
00551     Returns:    Init ok
00552     Purpose:    Calls InitFailed to delete the Tree and various others and follows this with 
00553                 an Init to put the Document back into a virgin state
00554                 Not used just yet...
00555     Errors:     
00556 
00557 ********************************************************************************************/
00558 
00559 BOOL Document::ReInit()
00560 {
00561     // RALPH
00562     InitFailed();
00563     return Init(OilDoc);
00564 
00565 /* 
00566     TreeStart->CascadeDelete();
00567     ERROR3IF(GetFirstNode() == NULL,"StartDoc not found"); 
00568     NodeDocument *Doc = (NodeDocument*)GetFirstNode()->FindNext(); 
00569     return InitTree(Doc);
00570 */
00571 
00572 //  return TRUE;
00573 
00574 }
00575 
00576 
00577 
00578 /********************************************************************************************
00579 
00580 >   BOOL Document::InitFailed(void)
00581 
00582     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00583     Created:    8/12/94
00584     Returns:    FALSE
00585     
00586     Purpose:    Called by Document::Init when it fails; encapsulates all necessary
00587                 tidying up, and then returns FALSE so that it can be called as part
00588                 of the final return statement.
00589                 Replaces some completely unnecessary goto code.
00590 
00591     SeeAlso:    Document::Init
00592 
00593 ********************************************************************************************/
00594 
00595 BOOL Document::InitFailed(void)
00596 {
00597     if (TreeStart != 0)
00598     {
00599         TreeStart->CascadeDelete();
00600         delete TreeStart;
00601         m_pSetSentinel = 0;
00602     }
00603 
00604     if (OpHistory != 0)
00605     {
00606         delete OpHistory;
00607         OpHistory = 0;
00608     }
00609     
00610     if (AttributeMgr != 0)
00611     {
00612         delete AttributeMgr;
00613         AttributeMgr = 0;
00614     }
00615 
00616     if (pDocUnitList != 0)
00617     {
00618         delete pDocUnitList;
00619         pDocUnitList = 0;
00620     }
00621     
00622     EndSlowJob();
00623     return(FALSE);
00624 }
00625 
00626 
00627 
00628 /***********************************************************************************************
00629 
00630 >   Document::~Document()
00631 
00632     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00633     Created:    19/5/93
00634     Purpose:    Destructor. Deletes the whole document tree of this object, and all memory
00635                 is returned to the heaps whence it came.  The busy cursor is displayed while
00636                 this is happening.
00637                                                                  
00638 ***********************************************************************************************/
00639 
00640 Document::~Document()
00641 {
00642     // Set the busy cursor . . .
00643     BeginSlowJob(-1, FALSE);
00644 
00645 #ifndef RALPH
00646     // Broadcast to everyone that this document is a dead duck.
00647     if (IsNotAHiddenDoc())
00648 #endif
00649     {
00650         // Document no longer stable.
00651         SetStable(FALSE);
00652         BROADCAST_TO_ALL(DocChangingMsg(this, DocChangingMsg::ABOUTTODIE));
00653     }
00654 
00655 
00656 #ifdef _DEBUG
00657         // DocViews should be closed before Documents, so all render regions for this document
00658         // should have been deleted - make sure they have.
00659         Camelot.DeleteRenderRegions(this);
00660 #endif
00661 
00662 #ifndef RALPH
00663     // Remove Document from list of all documents
00664     if (IsNotAHiddenDoc())
00665 #endif
00666     {
00667         Camelot.Documents.RemoveItem(this);
00668 
00669         // Is this the last document in the program?
00670         BOOL ThisIsTheLastDoc = (Camelot.Documents.GetHead() == NULL);
00671 
00672         if (ThisIsTheLastDoc)
00673         {
00674             // There are no more documents, so ensure that the system is in the correct state.
00675 
00676             // If the system is working correctly, then the following should be true:
00677             //   If Current  != NULL, Current  must be this document
00678             //   If Selected != NULL, Selected must be this document
00679             // We will ensure this is the case in debug builds
00680 
00681             ENSURE((Current  == NULL) || (Current  == this),"Current document is garbage");
00682             ENSURE((Selected == NULL) || (Selected == this),"Selected document is garbage");
00683 
00684             // Reset Current and Selected document and DocView
00685             SetNoCurrent();
00686             SetNoSelectedViewAndSpread();
00687 
00688             DocView::SetNoCurrent();
00689     //      DocView::SetNoSelected();   -- now done in SetNoSelectedViewAndSpread(), above
00690 
00691         }
00692         else
00693         {
00694             // Make sure that Current and Selected do not refer to the dying document
00695             if (this == Current)    SetNoCurrent();
00696             if (this == Selected)   SetNoSelectedViewAndSpread();
00697             
00698             // This special test added to fix a problem whereby current doc was being set to null
00699             // above and hence causing unit display problems (ERROR2s) in the selector tool when
00700             // opening a bitmap had been aborted. 18/9/96 Neville
00701             if (Selected != NULL && Current == NULL) Current = Selected; 
00702         }           
00703     }
00704 
00705     // Delete all DocViews attached to document
00706     DocViews.DeleteAll();
00707 
00708 #ifndef RALPH
00709     // Broadcast to everyone that this document is a dead duck.
00710     if (IsNotAHiddenDoc())
00711     {
00712         BROADCAST_TO_ALL(DocChangingMsg(this, DocChangingMsg::KILLED));
00713     }
00714 #endif  
00715     // Destroy the operation history. This must get destroyed before the tree is destroyed
00716     if (OpHistory != NULL)
00717         delete (OpHistory);   
00718 
00719     // Destroy the attribute manager 
00720     if (AttributeMgr != NULL)
00721         delete (AttributeMgr); 
00722 
00723     // Destroy the list of units in this document
00724     if (pDocUnitList != NULL)
00725         delete (pDocUnitList);
00726 
00727     // All done...
00728     EndSlowJob(); 
00729 
00730     // Note that the tree is deleted in the base class destructor
00731 }
00732 
00733 
00734 
00735 /********************************************************************************************
00736 >   BOOL Document::IsModified() const
00737 
00738     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00739     Created:    23/3/94
00740     Inputs:     -
00741     Outputs:    -
00742     Returns:    Returns TRUE if the document has been modified since last being saved.
00743     Purpose:    Tests the "Modified" flag.
00744     Errors:     -
00745     SeeAlso:    CCamDoc::IsModified
00746 ********************************************************************************************/
00747 
00748 BOOL Document::IsModified() const
00749 {
00750     if (OilDoc)
00751         return OilDoc->IsModified();
00752 
00753     return(FALSE);
00754 }
00755 
00756 
00757 
00758 /********************************************************************************************
00759 >   BOOL Document::IsReadOnly() const
00760 
00761     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00762     Created:    23/3/94
00763     Inputs:     -
00764     Outputs:    -
00765     Returns:    Returns TRUE if the document is read-only, ie. cannot be modified.
00766     Purpose:    Tests the "Read Only" flag.
00767     Errors:     -
00768     SeeAlso:    CCamDoc::IsReadOnly
00769 ********************************************************************************************/
00770 
00771 BOOL Document::IsReadOnly() const
00772 {
00773     if (OilDoc)
00774         return OilDoc->IsReadOnly();
00775 
00776     return(FALSE);
00777 }
00778 
00779 
00780 
00781 /********************************************************************************************
00782 >   BOOL Document::IsACopy() const
00783 
00784     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00785     Created:    23/3/94
00786     Inputs:     -
00787     Outputs:    -
00788     Returns:    Returns TRUE if the document is a copy of another document.
00789     Purpose:    Tests the "Copy" flag.
00790     Errors:     -
00791     SeeAlso:    CCamDoc::IsACopy
00792 ********************************************************************************************/
00793 
00794 BOOL Document::IsACopy() const
00795 {
00796     if (OilDoc)
00797         return OilDoc->IsACopy();
00798 
00799     return(FALSE);
00800 }
00801 
00802 
00803 
00804 /********************************************************************************************
00805 >   void Document::SetModified(BOOL fState = TRUE)
00806 
00807     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00808     Created:    23/3/94
00809     Inputs:     -
00810     Outputs:    -
00811     Returns:    -
00812     Purpose:    Sets (or clears) the "document is modified" flag.
00813     Errors:     -
00814     SeeAlso:    CCamDoc::SetModified
00815 ********************************************************************************************/
00816 
00817 void Document::SetModified(BOOL fState /* = TRUE */)
00818 {
00819     if (OilDoc)
00820         OilDoc->SetModified( fState != FALSE );
00821 }
00822 
00823 /********************************************************************************************
00824 >   void Document::IsLoadedAsVersion1File() const
00825 
00826     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00827     Created:    30/7/96
00828     Inputs:     -
00829     Outputs:    -
00830     Returns:    -
00831     Purpose:    Returns the current state of the IsLoadedAsVersion1File flag.
00832                 Flag to say that the document was loaded as a version 1 file
00833                 and so the user needs to be given the option of saving it in this form
00834                 when the document is saved
00835 ********************************************************************************************/
00836 
00837 BOOL Document::IsLoadedAsVersion1File() const
00838 {
00839     return LoadedAsVersion1File;
00840 }
00841 
00842 /********************************************************************************************
00843 >   BOOL Document::ISetLoadedAsVersion1File(BOOL NewState)
00844 
00845     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00846     Created:    30/7/96
00847     Inputs:     New state of the flag required
00848     Outputs:    -
00849     Returns:    Old state of the flag
00850     Purpose:    Sets a new current state of the IsLoadedAsVersion1File flag.
00851                 Flag to say that the document was loaded as a version 1 file
00852                 and so the user needs to be given the option of saving it in this form
00853                 when the document is saved
00854 ********************************************************************************************/
00855 
00856 BOOL Document::SetLoadedAsVersion1File(BOOL NewState)
00857 {
00858     BOOL OldState = LoadedAsVersion1File;
00859     LoadedAsVersion1File =  NewState;
00860     return OldState;
00861 }
00862 
00863 
00864 
00865 
00866 
00867 /********************************************************************************************
00868 >   BOOL Document::CreateDragTargets()
00869 
00870     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00871     Created:    22/1/95
00872     Inputs:     -
00873     Outputs:    -
00874     Returns:    -
00875     Purpose:    Calls all (OILY) views to create their drag targets.
00876     Errors:     -
00877     SeeAlso:    CCamDoc::SetModified
00878 ********************************************************************************************/
00879 
00880 BOOL Document::CreateDragTargets(DragInformation * DragInfo)
00881 {
00882     if (IsNotAClipboard())
00883     {
00884         DocView * Ptr= (DocView*) DocViews.GetHead();
00885         CCamView* TheView;
00886 
00887         while(Ptr)
00888         {
00889             TheView = Ptr->GetConnectionToOilView();
00890             if(TheView)
00891                     TheView->CreateDragTarget(DragInfo);
00892             Ptr= (DocView*) DocViews.GetNext(Ptr);
00893         }
00894     }
00895     return TRUE;
00896 }
00897 
00898 
00899 
00900 /********************************************************************************************
00901 
00902 >   String_256 Document::GetTitle() const
00903 
00904     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00905     Created:    15/3/94
00906     Returns:    A String_256 that holds the document title
00907     Purpose:    Returns the Title of the document. The title is the text that appears in the
00908                 documents windows (when it is not maximised). For example 'Untitled #1' or
00909                 'Untitled #1 (Modified)' or even 'Blobby.art (Modified)'.
00910     SeeAlso:    Document::GetProducer; Document::GetComment; CCamDoc::GetKernelTitle
00911 
00912 ********************************************************************************************/
00913 
00914 String_256 Document::GetTitle() const
00915 {
00916     if (OilDoc)
00917         return OilDoc->GetKernelTitle();
00918 
00919     return(ClipboardNameText);
00920 }
00921 
00922 
00923 /********************************************************************************************
00924 
00925 >   String_256 Document::GetDocName(BOOL IncludeFileType = TRUE) const
00926 
00927     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00928     Created:    27/3/95
00929     Inputs:     IncludeFileType - TRUE if the filetype is required. Defaults to TRUE.
00930     Returns:    A String_256 that holds the document name
00931     Purpose:    Returns the name of the document. The name will be the first part of the title
00932                 which is the text that appears in the document windows (when it is not maximised). For example 'Untitled #1' or
00933                 'Untitled #1 (Modified)' or even 'Blobby.art (Modified)'.
00934     SeeAlso:    Document::GetTitle(); CCamDoc::GetKernelTitle(); CCamDoc::GetKernelDocName();
00935     SeeAlso:    Document::GetProducer; Document::GetComment; 
00936 
00937 ********************************************************************************************/
00938 
00939 String_256 Document::GetDocName(BOOL IncludeFileType) const
00940 {
00941     if (OilDoc)
00942         return OilDoc->GetKernelDocName(IncludeFileType);
00943 
00944     return(ClipboardNameText);
00945 }   
00946 
00947 
00948 /********************************************************************************************
00949 
00950 >   String_256 Document::GetPathName(UINT32 MaxSize = 0) const
00951 
00952     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00953     Created:    20/3/95
00954     Inputs:     MaxSize - This is the size we have to fit the pathname into.
00955                 Defaults to zero , meaning all off the pathname.
00956     Returns:    A String_256 that holds the pathname for the document.
00957     Purpose:    Returns the pathname of the document.
00958     SeeAlso:    CCamDoc::GetKernelPathName; PathName::GetTruncatedPathName;
00959     SeeAlso:    Document::GetLocation; CCamDoc::GetTruncatedLocation;
00960 
00961 ********************************************************************************************/
00962 
00963 String_256 Document::GetPathName(UINT32 MaxSize) const
00964 {
00965     if (OilDoc)
00966         return OilDoc->GetKernelPathName(MaxSize);
00967 
00968     return(ClipboardNameText);
00969 }
00970 
00971 /********************************************************************************************
00972 
00973 >   String_256 Document::GetLocation(UINT32 MaxSize = 0) const
00974 
00975     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00976     Created:    20/3/95
00977     Inputs:     MaxSize - This is the size we have to fit the pathname into.
00978                 Defaults to zero , meaning all off the pathname.
00979     Returns:    A String_256 that holds the location for the document.
00980     Purpose:    Returns the location of the document, which is the pathname with no filename.
00981     SeeAlso:    CCamDoc::GetKernelLocation; PathName::GetTruncatedLocation;
00982     SeeAlso:    Document::GetPathName; CCamDoc::GetKernelPathName;
00983 
00984 ********************************************************************************************/
00985 
00986 String_256 Document::GetLocation(UINT32 MaxSize) const
00987 {
00988     if (OilDoc)
00989         return OilDoc->GetKernelLocation(MaxSize);
00990 
00991     return(ClipboardNameText);
00992 }
00993 
00994 
00995 /********************************************************************************************
00996 >   const String_256& Document::GetProducer() const
00997 
00998     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00999     Created:    15/3/94
01000     Inputs:     -
01001     Outputs:    -
01002     Returns:    A reference to the (constant) producer's name of this document.
01003     Purpose:    
01004     Errors:     -
01005     SeeAlso:    Document::GetTitle; Document::GetComment
01006 ********************************************************************************************/
01007 
01008 const String_256& Document::GetProducer() const
01009 {
01010     return Producer;
01011 }
01012 
01013 
01014 
01015 /********************************************************************************************
01016 >   const String_256& Document::GetComment() const
01017 
01018     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01019     Created:    15/3/94
01020     Inputs:     -
01021     Outputs:    -
01022     Returns:    A reference to the (constant) producer's name of this document.
01023     Purpose:    Getting the time the document was created.
01024     Errors:     -
01025     SeeAlso:    Document::GetTitle; Document::GetProducer
01026 ********************************************************************************************/
01027 
01028 const String_256& Document::GetComment() const
01029 {
01030     return Comment;
01031 }
01032 
01033 
01034 
01035 /********************************************************************************************
01036 >   void Document::SetComment(String_256* NewComment)
01037 
01038     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01039     Created:    31/8/94
01040     Inputs:     A pointer to the new comment string.
01041     Outputs:    -
01042     Returns:    -
01043     Purpose:    Setting the document's comment string.
01044     Errors:     -
01045     SeeAlso:    Document::GetComment
01046 ********************************************************************************************/
01047 
01048 void Document::SetComment(String_256* NewComment)
01049 {
01050     Comment = *NewComment;
01051 }
01052 
01053 
01054 
01055 /********************************************************************************************
01056 >   const time_t& Document::GetCreationTime() const
01057 
01058     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01059     Created:    31/08/94
01060     Inputs:     -
01061     Outputs:    -
01062     Returns:    A reference to the time of the document's creation.
01063     Purpose:    
01064     Errors:     -
01065     SeeAlso:    Document::GetLastSaveTime
01066 ********************************************************************************************/
01067 
01068 const time_t& Document::GetCreationTime() const
01069 {
01070     return CreationTime;
01071 }
01072 
01073 
01074 
01075 /********************************************************************************************
01076 >   const time_t& Document::GetLastSaveTime() const
01077 
01078     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01079     Created:    31/08/94
01080     Inputs:     -
01081     Outputs:    -
01082     Returns:    A reference to the time of the document's creation.  Will be 0 if the
01083                 document is unsaved.
01084     Purpose:    Getting the time the document was last saved.
01085     Errors:     -
01086     SeeAlso:    Document::GetCreationTime
01087 ********************************************************************************************/
01088                 
01089 const time_t& Document::GetLastSaveTime() const
01090 {
01091     return LastSaveTime;
01092 }
01093 
01094 
01095 
01096 /********************************************************************************************
01097 >   void Document::SetLastSaveTime() const
01098 
01099     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01100     Created:    1/09/94
01101     Inputs:     -
01102     Outputs:    -
01103     Returns:    -
01104     Purpose:    Call on saving a document.  Sets the document's last saved time.
01105     Errors:     -
01106     SeeAlso:    Document::GetLastSaveTime
01107 ********************************************************************************************/
01108 
01109 void Document::SetLastSaveTime()
01110 {
01111     LastSaveTime = ::time(NULL);
01112 }
01113 
01114 /********************************************************************************************
01115 >   void Document::SetLastSaveTime(time_t)
01116 
01117     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01118     Created:    30/7/96
01119     Inputs:     -
01120     Outputs:    -
01121     Returns:    -
01122     Purpose:    Allows setting of the document's last saved time.
01123     Errors:     -
01124     SeeAlso:    Document::GetLastSaveTime
01125 ********************************************************************************************/
01126 
01127 void Document::SetLastSaveTime(time_t NewTime)
01128 {
01129     LastSaveTime = NewTime;
01130 }
01131 
01132 /********************************************************************************************
01133 >   void Document::SetCreationTime(time_t)
01134 
01135     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01136     Created:    30/7/96
01137     Inputs:     -
01138     Outputs:    -
01139     Returns:    -
01140     Purpose:    Allows setting of the document's creation time.
01141     Errors:     -
01142     SeeAlso:    Document::GetLastSaveTime
01143 ********************************************************************************************/
01144 
01145 void Document::SetCreationTime(time_t NewTime)
01146 {
01147     CreationTime = NewTime;
01148 }
01149 
01150 /********************************************************************************************
01151 >   void Document::MakeJustCreated()
01152 
01153     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01154     Created:    11/5/95
01155     Inputs:     -
01156     Outputs:    Sets member variables
01157     Returns:    -
01158     Purpose:    Resets member variables of the document so it abbears as if the document has
01159                 just been created (eg CreationTime is set to the current time)
01160     Errors:     -
01161     SeeAlso:    -
01162 ********************************************************************************************/
01163 void Document::MakeJustCreated()
01164 {
01165     LastSaveTime = 0;               // Zero means not saved
01166     CreationTime = ::time(NULL);
01167 }
01168 
01169 
01170 
01171 /********************************************************************************************
01172 
01173 >   void Document::InsertNewNode( Node* NewNode, DocCoord* Point )
01174 
01175     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01176     Created:    3/9/93
01177     Inputs:     NewNode - A Pointer to the New node to be inserted
01178                 pDestSpread - pointer to the spread  which this new node should be
01179                               inserted, If this is NULL then the object is inserted
01180                               on the selected spread.
01181 
01182     Purpose:    Inserts the Node into the Document at the position specified.
01183                 The node is added to the active layer on this spread 
01184     SeeAlso:    Document::FindEnclosingChapter(); Document::FindEnclosingPage()
01185 
01186 ********************************************************************************************/
01187 
01188 void Document::InsertNewNode( Node* NewNode, Spread *pDestSpread )
01189 {
01190     SetCurrent();
01191 
01192     Node *pNode; 
01193 
01194     // Most of the time we will be inserting onto the selected spread
01195     // So find out what this is.
01196     
01197     if ((pDestSpread == NULL) || (pDestSpread == Document::GetSelectedSpread()))
01198     {
01199         // We need to insert the node onto the selected spread. This is very quick because we
01200         // keep an Insertion node there.
01201         pNode = GetInsertionPosition(); 
01202         ENSURE(pNode != NULL, "Could not find insertion position in Document::InsertNewNode()");
01203         // Attach the node to the left of the insertion node
01204         NewNode -> AttachNode( pNode, PREV );
01205 
01206     } 
01207     else
01208     {
01209         // This is assuming that we are inserting into the non-selected spread and so does
01210         // not use the insertion position. Unfortunately, there is a chance that this MAY happen
01211         // as the selected spread may be in a different document and so we are inserting into a
01212         // single spread document with an insertion node. The code below will insert AFTER the
01213         // insertion node and so will be in an illegal position. We really should check this!!!
01214         // As we are close to release I will put an error 3 in just in case. Neville 24/9/96
01215         TRACE( _T("\aDocument::InsertNewNode inserting into the unselected spread. Is this correct?\n") );
01216 
01217         pNode = pDestSpread->FindActiveLayer();
01218         ENSURE(pNode != NULL, "Could not find layer in Document::InsertNewNode()");
01219         // Attach this node to the tree at this point
01220         NewNode -> AttachNode( pNode, LASTCHILD );
01221     }
01222 }
01223 
01224 
01225 
01226 /***********************************************************************************************
01227 
01228     DocView *Document::GetSpareDocView()
01229 
01230     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01231     Created:    19/5/93
01232     
01233     Inputs:     - 
01234     Outputs:    -
01235     Returns:    NULL, or a spare DocView
01236                  
01237     Purpose:    Looks for a DocView with no attached OilView, so we can recycle it
01238                
01239     Errors:     None.
01240                                                                  
01241 ***********************************************************************************************/
01242 
01243 DocView* Document::GetSpareDocView()
01244 {
01245     if (IsNotAClipboard())
01246     {
01247         DocView *View = (DocView *) DocViews.GetHead();
01248     
01249         while (View != NULL)
01250         {
01251             CCamView *pCamView = View->GetConnectionToOilView();
01252             if (pCamView == NULL) return View;
01253             View = (DocView *) DocViews.GetNext(View);
01254         }
01255     }
01256 
01257     return NULL;        // No free views found
01258 }
01259 
01260 
01261 
01262 /***********************************************************************************************
01263 
01264 >   DocView* Document::GetNewDocView()
01265 
01266     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01267     Created:    19/5/93
01268     
01269     Inputs:     -