// $Id: finfodlg.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 the FileInfo class - copied from AboutDlg /* */ #include "camtypes.h" DECLARE_SOURCE("$Revision: 1282 $"); #include "camelot.h" //#include "dlgtypes.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "finfodlg.h" //#include "mario.h" // for string resource //#include "peter.h" // for string resources //#include "reshlpid.h" // for help resources //#include "peterdlg.h" // for dialogue resources //#include "document.h" // for reading and setting document attributes - in camtypes.h [AUTOMATICALLY REMOVED] #include "localenv.h" // for locale string settings //#include "node.h" // for tree scanning calls - in camtypes.h [AUTOMATICALLY REMOVED] //#include "spread.h" // for Spread - in camtypes.h [AUTOMATICALLY REMOVED] #include "page.h" // for Page //#include "group.h" // for NodeGroup - in camtypes.h [AUTOMATICALLY REMOVED] #include "nodebmp.h" // for NodeBitmap #include "bitmpinf.h" // for BitmapInfo //#include "app.h" // for GetApplication - in camtypes.h [AUTOMATICALLY REMOVED] //#include "convert.h" // for StringToBytes and BytesToString - in camtypes.h [AUTOMATICALLY REMOVED] #include "nodetxts.h" // for TextStory node. #include "fontlist.h" // for the document font list #include "progress.h" //#include "barsdlgs.h" // for the document info file bar controls #include "fontman.h" #include "bubbleid.h" //#include "customlist.h" //#include "richard.h" //#include "will2.h" //#include "opdesc.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "ophist.h" // Required for the document font combo box handling #include "fontman.h" #include "fontdrop.h" #include "fontbase.h" #include "nodeliveeffect.h" CC_IMPLEMENT_DYNCREATE(FileInfo, DialogOp) CC_IMPLEMENT_DYNCREATE(RefItem, ListItem) #define new CAM_DEBUG_NEW const CDlgMode FileInfo::Mode = MODELESS; // The dialog is modal (for the moment.) const UINT32 FileInfo::IDD = _R(IDD_FINFODLG); FileInfo * FileInfo::CurrentDialog = NULL; DocumentFontDropDown *FileInfo::NameDropDown = NULL; // Font name drop-down list which shows document fonts // Timing constants #define DURATION_FASTJOB 500 // Half a second #define DURATION_SLOWJOB 10*1000 // Ten seconds /******************************************************************************************* > FileInfo::FileInfo(): DialogOp(FileInfo::IDD, FileInfo::Mode) Author: Peter_Arnold (Xara Group Ltd) Created: 23/08/94 Inputs: - Outputs: - Returns: - Purpose: FileInfo constructor Errors: - SeeAlso: - *******************************************************************************************/ FileInfo::FileInfo(): DialogOp(FileInfo::IDD, FileInfo::Mode) { } /******************************************************************************************* > FileInfo::~FileInfo() Author: Peter_Arnold (Xara Group Ltd) Created: 22/09/94 Inputs: - Outputs: - Returns: - Purpose: FileInfo destructor - deallocate the BitmapList space Errors: - SeeAlso: - *******************************************************************************************/ FileInfo::~FileInfo() { BitmapList.DeleteAll(); CurrentDialog = NULL; // Jim, 5/8/96 // Delete a Drop Down list if it's been created (via a static, of all things!) // This removes a memory leak. (And should have been here all the time.) if (NameDropDown != NULL) { delete NameDropDown; NameDropDown = NULL; } } /******************************************************************************************* > MsgResult FileInfo::Message(Msg* Message); Author: Peter_Arnold (Xara Group Ltd) Created: 23/08/94 Inputs: - Outputs: - Returns: - Purpose: Handles all the File info dialog's messages Errors: - SeeAlso: - *******************************************************************************************/ MsgResult FileInfo::Message(Msg* Message) { if (IS_OUR_DIALOG_MSG(Message)) { DialogMsg* Msg = (DialogMsg*)Message; if (Msg->DlgMsg == DIM_CREATE) { OnDimCreate(); } if ((Msg->DlgMsg == DIM_COMMIT) || (Msg->DlgMsg == DIM_SOFT_COMMIT)) { Document* WorkDoc = Document::GetSelected(); if (WorkDoc != NULL) { String_256 NewComment = GetStringGadgetValue(_R(IDC_FILEINFO_COMMENT), NULL, -1); String_256 OldComment = WorkDoc->GetComment(); if (NewComment != OldComment) { WorkDoc->SetComment(&NewComment); WorkDoc->SetModified(TRUE); } } } if ((Msg->DlgMsg == DIM_COMMIT) || (Msg->DlgMsg == DIM_CANCEL)) { Close(); // Close and destroy the dialog End(); // return (DLG_EAT_IF_HUNGRY(Msg)); } if (Msg->DlgMsg == DIM_TIMER) { SetDocInfo(FALSE, timerSlowJob.Elapsed(DURATION_SLOWJOB, TRUE)); // Don't update comment field } } if (MESSAGE_IS_A(Message, DocChangingMsg)) { DocChangingMsg* DocMsg = (DocChangingMsg*) Message; if (DocMsg->State == DocChangingMsg::SELCHANGED) { if (DocMsg->pOldDoc != NULL) { String_256 NewComment = GetStringGadgetValue(_R(IDC_FILEINFO_COMMENT), NULL, -1); String_256 OldComment = DocMsg->pOldDoc->GetComment(); if (NewComment != OldComment) { DocMsg->pOldDoc->SetComment(&NewComment); DocMsg->pOldDoc->SetModified(TRUE); } } SetDocInfo(TRUE,TRUE); } } // return OK; return DialogOp::Message(Message); } /******************************************************************************************* > BOOL FileInfo::OnDimCreate() Author: Phil_Martin (Xara Group Ltd) Created: 01/02/2005 Inputs: - Outputs: - Returns: - Purpose: Initialises the contents of the File Info dialog when it is first created Errors: - SeeAlso: - *******************************************************************************************/ BOOL FileInfo::OnDimCreate() { // Setup callback timer this->SetTimer(42, DURATION_FASTJOB); // Ten seconds between updates timerSlowJob.Sample(); // Setup list columns // Why do we do this here when we have to use a custom AddItem function (AddRefsItem) // to populate the list? CCustomList* pListGadget = CCustomList::GetGadget(GetReadWriteWindowID(), _R(IDC_FINFO_REFSLIST)); ERROR2IF(pListGadget==NULL, FALSE, "No refs list gadget"); // pListGadget->ShowColumnHeaders("", "Item", "Details"); pListGadget->SetColumnWidth(0, 14); // Status indicators pListGadget->SetColumnWidth(1, 80); // Item name pListGadget->SetColumnWidth(2, 760); // Details SetDocInfo(TRUE, TRUE); return TRUE; } /******************************************************************************************* > OpState FileInfo::GetState(String_256*, OpDescriptor*) Author: Peter_Arnold (Xara Group Ltd) Created: 23/08/94 Inputs: - Outputs: - Returns: - Purpose: Returns the OpState of the file info dialogue operation Errors: - SeeAlso: - *******************************************************************************************/ OpState FileInfo::GetState(String_256*, OpDescriptor*) { return OpState(FALSE, (Document::GetSelected() == NULL)); } /******************************************************************************************* > BOOL FileInfo::Init() Author: Peter_Arnold (Xara Group Ltd) Created: 23/08/94 Inputs: - Outputs: - Returns: FALSE if it fails (due to lack of memory) Purpose: Creates an OpDescriptor for a file info dialog Errors: - SeeAlso: - *******************************************************************************************/ BOOL FileInfo::Init() { return RegisterOpDescriptor( 0, // Tool ID _R(IDS_FILE_INFO), // String resouirce ID CC_RUNTIME_CLASS(FileInfo), // Runtime class OPTOKEN_FINFODLG, // Token string FileInfo::GetState, // GetState function 0, // Help ID _R(IDBBL_FILEINFO), // Bubble ID _R(IDD_BARCONTROLSTORE), // Resource ID _R(IDC_FILEINFO), // Control ID SYSTEMBAR_FILE, // Bar ID TRUE, // Recieve system messages FALSE, // Smart duplicate operation TRUE, // Clean operation 0, // No vertical counterpart _R(IDS_FILEINFO_ONE), // String for one copy only (DONT_GREY_WHEN_SELECT_INSIDE | GREY_WHEN_NO_CURRENT_DOC) // Auto state flags ); } /******************************************************************************************* > void FileInfo::Do(OpDescriptor*) Author: Peter_Arnold (Xara Group Ltd) Created: 23/08/94 Inputs: - Outputs: - Returns: - Purpose: Creates and shows a file info dialog Errors: - SeeAlso: - *******************************************************************************************/ void FileInfo::Do(OpDescriptor*) { Create(); Open(); CurrentDialog = this; } /******************************************************************************************* > void FileInfo::Refresh() Author: Chris_Snook (Xara Group Ltd) Created: 10/05/95 Inputs: - Outputs: - Returns: - Purpose: Can be called by anyone to force an update Errors: - SeeAlso: - *******************************************************************************************/ void FileInfo::Refresh() { if (CurrentDialog) CurrentDialog->SetDocInfo(TRUE,TRUE); } /******************************************************************************************* > BOOL FileInfo::UpdateFontList(Document* WorkDoc) Author: Neville_Humphrys (Xara Group Ltd) Created: 13/11/95 Inputs: WorkDoc pointer to the document we are working on, NULL if no document Outputs: - Returns: True if completed ok, False otherwise. Purpose: Updates the font name list with the current list of fonts in the selected document. If no fonts are present then shows this by using a blank list and putting a suitable message in the top item. If the specified document is null then will just show a blank list with a dashed and greyed top item. Errors: - SeeAlso: SetDocInfo; FontDropDown; DocumentFontDropDown; *******************************************************************************************/ BOOL FileInfo::UpdateFontList(Document* WorkDoc) { CCustomList* pListGadget = CCustomList::GetGadget(GetReadWriteWindowID(), _R(IDC_FINFO_REFSLIST)); ERROR2IF(pListGadget == NULL, FALSE, "No list gadget?!"); List ItemList; // Build the font list for the specified document // This will NOT be alphabetical FontListItem* FontItem = NULL; if (WorkDoc) { FontList DocFonts; DocFonts.Build(WorkDoc); FontItem = DocFonts.GetFirstItem(); // fill up the list while (FontItem != NULL) { // get the name UINT32 idBitmap = 0; String_64 strName = FontItem->GetFontName(); String_256 strDetails; WORD Handle = FONTMANAGER->GetFontHandle(&strName); // check the style INT32 Style = FontItem->GetFontStyle(); if (Style & 1) strName += _T(" -Bold"); if (Style & 2) strName += _T(" -Italic"); if (Handle > 0) { if (FONTMANAGER->IsFontReplaced(Handle)) strDetails = String(_R(IDS_FINFO_FONTNOTINSTALLED)); } FontClass Type = FontItem->GetFontClass(); switch(Type) { case FC_TRUETYPE: idBitmap = _R(IDB_TTF_SYMBOL); break; case FC_ATM: idBitmap = _R(IDB_ATM_SYMBOL); break; default: idBitmap = 0; break; } AddToSortedList(ItemList, idBitmap, strName, strDetails); FontItem = DocFonts.GetNextItem(FontItem); ContinueSlowJob(); } } // Put the sorted items in the list gadget RefItem* pRefItem = (RefItem*)ItemList.GetHead(); while (pRefItem) { // Add the font in the list to the list box pListGadget->AddRefsItem(pRefItem->idBitmap, pRefItem->strItemName, pRefItem->strDetails); pRefItem = (RefItem*)ItemList.GetNext(pRefItem); } ItemList.DeleteAll(); return TRUE; } /******************************************************************************************* > BOOL FileInfo::UpdateEffectsList(Document* pWorkDoc) Author: Phil_Martin (Xara Group Ltd) Created: 31/01/2005 Inputs: WorkDoc pointer to the document we are working on, NULL if no document Outputs: - Returns: True if completed ok, False otherwise. Purpose: Updates the effects list showing referred and missing effects Errors: - SeeAlso: SetDocInfo; FontDropDown; DocumentFontDropDown; *******************************************************************************************/ BOOL FileInfo::UpdateEffectsList(Document* pWorkDoc) { // 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 CCustomList* pListGadget = CCustomList::GetGadget(GetReadWriteWindowID(), _R(IDC_FINFO_REFSLIST)); ERROR2IF(pListGadget == NULL, FALSE, "No list gadget?!"); if (pWorkDoc == NULL) // Don't try to fill in anything when the window is shaded { return TRUE; } List ItemList; PORTNOTE("other", "Disabled bitmap effects") #ifndef EXCLUDE_FROM_XARALX ListRange* pEffectList = pWorkDoc->GetEffectsList(500000); // Arbitrary large number if (pEffectList) { // Now add listed items to the ListBox INT32 index = 0; Node* pNode = pEffectList->FindFirst(); while (pNode) { ENSURE(pNode->IsBitmapEffect(), "How can this node not be a BitmapEffect?"); if (pNode->IsBitmapEffect()) { NodeBitmapEffect* pEffect = (NodeBitmapEffect*)pNode; String_64 strEffectName = pEffect->GetDisplayName(); String_256 strDetails; UINT32 idBitmap = 0; if (pEffect->IsLockedEffect()) { // Destructive/locked effects have their own bitmap stored in them // So we don't need to test whether their handler is installed on this machine String_64 strFoundDisplayName; BOOL bFound = XPEHost::GetEffectDetails(pEffect->GetPostProcessorID(), &strFoundDisplayName); if (bFound) { strDetails = String(_R(IDS_FINFO_EFFECTOK)); idBitmap = _R(IDB_FINFO_OKEFFECT); } else { strDetails = String(_R(IDS_FINFO_LOCKEDEFFECT)); idBitmap = _R(IDB_FINFO_LOCKEDEFFECT); } } else { // Live effects need to regenerate their bitmaps so we must // test whether the handler is present and warn the user if not String_64 strFoundDisplayName; BOOL bFound = XPEHost::GetEffectDetails(pEffect->GetPostProcessorID(), &strFoundDisplayName); if (bFound) { strDetails = String(_R(IDS_FINFO_EFFECTOK)); idBitmap = _R(IDB_FINFO_OKEFFECT); } else { strDetails = String(_R(IDS_FINFO_NOTFOUND)); strDetails += String(" ["); strDetails += pEffect->GetPostProcessorID(); strDetails += String("]"); idBitmap = _R(IDB_FINFO_MISSINGEFFECT); } } AddToSortedList(ItemList, idBitmap, strEffectName, strDetails); ContinueSlowJob(); } pNode = pEffectList->FindNext(pNode); } delete pEffectList; pEffectList = NULL; } #endif // Put the sorted items in the list gadget RefItem* pRefItem = (RefItem*)ItemList.GetHead(); while (pRefItem) { // Add the font in the list to the list box pListGadget->AddRefsItem(pRefItem->idBitmap, pRefItem->strItemName, pRefItem->strDetails); pRefItem = (RefItem*)ItemList.GetNext(pRefItem); } ItemList.DeleteAll(); return TRUE; } /******************************************************************************************* > BOOL FileInfo::SetDocInfo(BOOL UpdateComment, BOOL UpdateFonts) Author: Peter_Arnold (Xara Group Ltd) Created: 25/08/94 Inputs: UpdateComment - TRUE if the comment field should be updated. Normally FALSE for fast updates (otherwise the comment field looses newly entered text). UpdateFonts - TRUE if we want to update the font list avoid if possible as this causes a rebuild of the font list and much flicker.. Outputs: - Returns: - Purpose: Sets the values in the fields of the document information dialogue. Errors: - SeeAlso: - *******************************************************************************************/ BOOL FileInfo::SetDocInfo(BOOL UpdateComment, BOOL UpdateFonts) { Document* WorkDoc = Document::GetSelected(); if (UpdateFonts) { BeginSlowJob(); GadgetRedraw(_R(IDC_FINFO_REFSLIST), FALSE); // Disable redraw while updating CCustomList* pListGadget = CCustomList::GetGadget(GetReadWriteWindowID(), _R(IDC_FINFO_REFSLIST)); ERROR2IF(pListGadget == NULL, FALSE, "No list gadget?!"); INT32 iSelectedItem = pListGadget->GetSelectedItemIndex(); INT32 iScrollPos = pListGadget->GetScrollPos(SB_VERT); pListGadget->DeleteAllItems(); // Work out all the document based fonts again and recreate the drop down list pListGadget->AddRefsItem(0, String(_R(IDS_FINFO_FONTREFS_NAMEHEADER)), String(_R(IDS_FINFO_FONTREFS_DETAILSHEADER))); UpdateFontList(WorkDoc); // Show effects usage pListGadget->AddRefsItem(0, String(_R(IDS_FINFO_EFFECTREFS_NAMEHEADER)), String(_R(IDS_FINFO_EFFECTREFS_DETAILSHEADER))); UpdateEffectsList(WorkDoc); pListGadget->SetSelectedItemIndex(iSelectedItem); pListGadget->SetScrollPos(SB_VERT, iScrollPos, FALSE); GadgetRedraw(_R(IDC_FINFO_REFSLIST), TRUE); // Enable redraw while updating InvalidateGadget(_R(IDC_FINFO_REFSLIST)); // Force redraw now that we're done EndSlowJob(); } // If there is no selected document then we want to set the fields to be blank if (WorkDoc == NULL) { String_8 DashString(_R(IDS_K_FINFODLG_DASH)); String_8 NullString = _T(""); UpdateStringGadgetValue(_R(IDC_FILEINFO_UNDOSIZE), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_UNDOSTEPS), &DashString); // UpdateStringGadgetValue(_R(IDC_FILEINFO_SPREADS), &DashString); // UpdateStringGadgetValue(_R(IDC_FILEINFO_PAGES), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_NUMOBJECTS), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_NUMSELOBJECTS), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_LOCATION), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_FILENAME), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_FILESIZE), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_NUMBITMAPS), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_BITMAPSIZE), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_FRACTALS), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_FRACTALSIZE), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_CREATIONDATE), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_LASTSAVEDATE), &DashString); UpdateStringGadgetValue(_R(IDC_FILEINFO_COMMENT), &NullString); return TRUE; } // Declare the general strings we use throughout String_256 String; String_256 String2; // Keep a list of the bitmaps that we have found in our scan so that we do not // count the same bitmap twice BitmapList.DeleteAll(); // -- // -- Display the undo and redo steps for the document // -- // Now calculate the size of the undo buffer and if any records have been discarded Convert::BytesToString(&String, WorkDoc->GetOpHistory().GetSize()); if (WorkDoc->GetOpHistory().IsReduced()) { String2.MakeMsg(_R(IDS_FILEINFO_REDUCED)); String += String2; } UpdateStringGadgetValue(_R(IDC_FILEINFO_UNDOSIZE), &String); // Now calculate the number of undo and redo steps UINT32 UndoSteps = WorkDoc->GetOpHistory().GetNumUndoSteps(); UINT32 RedoSteps = WorkDoc->GetOpHistory().GetNumRedoSteps(); String = ""; if (UndoSteps != 0) { String.MakeMsg(_R(IDS_FILEINFO_UNDOSTEPS), UndoSteps); if (UndoSteps == 1) String2.MakeMsg(_R(IDS_FILEINFO_STEP)); else String2.MakeMsg(_R(IDS_FILEINFO_STEPS)); String += String2; } if (RedoSteps != 0) { String_256 String3; String2.MakeMsg(_R(IDS_FILEINFO_REDOSTEPS), RedoSteps); if (String.CompareTo(_T("")) != 0) String += String_64(_R(IDS_K_FINFODLG_SEPERATOR)); if (RedoSteps == 1) String3.MakeMsg(_R(IDS_FILEINFO_STEP)); else String3.MakeMsg(_R(IDS_FILEINFO_STEPS)); String += String2; String += String3; } if (String.CompareTo(_T("")) == 0) { String.MakeMsg(_R(IDS_FILEINFO_NOSTEPS)); UpdateStringGadgetValue(_R(IDC_FILEINFO_UNDOSTEPS), &String); } else { UpdateStringGadgetValue(_R(IDC_FILEINFO_UNDOSTEPS), &String); } // -- // -- Display the comment field for the current document // -- // Update the comment field if we should if (UpdateComment) { String = WorkDoc->GetComment(); UpdateStringGadgetValue(_R(IDC_FILEINFO_COMMENT), &String); } // Now scan the document for the various object counts BitmapInfo BitInfo; Node* CurrentNode = StartTreeScan(WorkDoc); UINT32 Spreads = 0; UINT32 Pages = 0; UINT32 Bitmaps = 0; UINT32 BitmapSize = 0; UINT32 Objects = 0; UINT32 SelObjects = 0; UINT32 Groups = 0; UINT32 Size = 0; BOOL DontGetNext = TRUE; while (CurrentNode != NULL) { Size += CurrentNode->GetNodeSize(); DontGetNext = TRUE; if (CurrentNode->IsAnObject()) { // If it's a renderable object then count it. Objects ++; // This is silly as there is already a function to do this (SelRange::Count) // and using this method we won't be counting selected inside items. //if (CurrentNode->IsSelected()) //{ // SelObjects++; //} if (CurrentNode->IS_KIND_OF(NodeGroup) || IS_A(CurrentNode,TextStory)) { // Count objects inside groups, moulds and blends as one object // as these are renderable and would otherwise be included in the count. // Need to do the same with TextStories as these contain the renderable // text lines and text characters ... // Don't want to count objects inside groups (or blends) so sidestep Size += CurrentNode->GetSubtreeSize(); CurrentNode = SkipSubtreeScan(CurrentNode); DontGetNext = FALSE; // Increment our group count if this is a real group rather than a blend // or a mould or a text story. if (IS_A(CurrentNode,NodeGroup)) Groups++; } else { //// If it's a renderable object then count it. //// But objects like blends and moulds are renderable but shouldn't be //// counted as they are not true objects. //Objects ++; if (IS_A(CurrentNode,NodeBitmap)) { // We've found a bitmap, so we need to see whether it is in our list of // previously found bitmaps. If we have found it before then we can // ignore it. Otherwise, we add it to the list and add its size to our // size count. Bitmaps ++; NodeListItem* CurrentBitmapNode = (NodeListItem*)BitmapList.GetHead(); BOOL Found = FALSE; while (CurrentBitmapNode != NULL) { if ((((NodeBitmap*)CurrentBitmapNode->pNode)->GetBitmap()->ActualBitmap) == (((NodeBitmap*)CurrentNode)->GetBitmap()->ActualBitmap)) { Found = TRUE; } CurrentBitmapNode = (NodeListItem*)BitmapList.GetNext(CurrentBitmapNode); } if (!Found) { ((NodeBitmap*)CurrentNode)->GetBitmap()->ActualBitmap->GetInfo(&BitInfo); BitmapSize += BitInfo.MemoryUsed; CurrentBitmapNode = new NodeListItem(CurrentNode); BitmapList.AddHead(CurrentBitmapNode); } } } } else { // Increment specific non-renderable object counts. if (IS_A(CurrentNode,Spread)) { Spreads ++; } else { if (IS_A(CurrentNode,Page)) { Pages ++; } } } if ((CurrentNode != NULL) && DontGetNext) { CurrentNode = GetNextTreeNode(CurrentNode); } } // Now work out the number of objects that are currently selected // Find the application and hence the selection range Application* pApplication = GetApplication(); if (pApplication) { // First, check if there is a selection present. ClipRect should be empty if not. SelRange* pSelection = pApplication->FindSelection(); // If there is a selection then count it if (pSelection) { SelObjects = pSelection->Count(); } } // -- // -- Display number of pages and number of spreads in the document // -- // No longer required as only one spread in version 1.0 // String._MakeMsg("#1%lu", Spreads); // UpdateStringGadgetValue(_R(IDC_FILEINFO_SPREADS), &String); // String._MakeMsg("#1%lu", Pages); // UpdateStringGadgetValue(_R(IDC_FILEINFO_PAGES), &String); // -- // -- Display number of objects and number of selected objects // -- // Show some of the information that we found String._MakeMsg(_T("#1%lu"), Objects); UpdateStringGadgetValue(_R(IDC_FILEINFO_NUMOBJECTS), &String); String._MakeMsg(_T("#1%lu"), SelObjects); UpdateStringGadgetValue(_R(IDC_FILEINFO_NUMSELOBJECTS), &String); // -- // -- Display count and size of fractals in the document // -- // Show the current number of fractals and bitmaps in this document // First the fractals. Application * Camelot = GetApplication(); EnumFractalData FracData; if (Camelot) { GlobalFractalList * FracList = Camelot->GetGlobalFractalList(); if (FracList) FracList->GetDocumentFractalData(WorkDoc,&FracData); } String._MakeMsg(_T("#1%lu"), FracData.Count); UpdateStringGadgetValue(_R(IDC_FILEINFO_FRACTALS), &String); Convert::BytesToString(&String, FracData.Size); UpdateStringGadgetValue(_R(IDC_FILEINFO_FRACTALSIZE), &String); // -- // -- Display count and size of bitmaps in the document // -- INT32 BitmapsCount = 0; INT32 BitmapsSize = 0; if (Camelot) { GlobalBitmapList * BmpList = Camelot->GetGlobalBitmapList(); if (BmpList) { BitmapsCount = BmpList->GetDocumentBitmapCount(WorkDoc); BitmapsSize = BmpList->GetDocumentBitmapSize(WorkDoc); } } //String._MakeMsg("#1%lu", Bitmaps); String._MakeMsg(_T("#1%lu"), BitmapsCount); UpdateStringGadgetValue(_R(IDC_FILEINFO_NUMBITMAPS), &String); //BytesToString(&String, BitmapSize); Convert::BytesToString(&String, BitmapsSize); UpdateStringGadgetValue(_R(IDC_FILEINFO_BITMAPSIZE), &String); // Now show our final size // Add in the number of bitmaps that we found as these will be saved with the // document. Don't include fractals as these are regenerated on loading. // Current thinking seems to be that we should show the fractals as well as this // field is now memory used. Size += BitmapsSize; Size += FracData.Size; Convert::BytesToString(&String, Size); UpdateStringGadgetValue(_R(IDC_FILEINFO_FILESIZE), &String); // -- // -- Display Location and Filename of document // -- // Show the current pathname for the document // The number give sthe size that we have to fit the pathname into. String.Empty(); //String = WorkDoc->GetPathName(45); String = WorkDoc->GetLocation(41); if ( String.IsEmpty() ) { // No pathname yet, so put in a nice message String.MakeMsg(_R(IDS_FILEINFO_UNSAVED)); } UpdateStringGadgetValue(_R(IDC_FILEINFO_LOCATION), &String); // Now show the current filename String.Empty(); String = WorkDoc->GetTitle(); UpdateStringGadgetValue(_R(IDC_FILEINFO_FILENAME), &String); // -- // -- Display Creation and Save times for the document // -- // Now do the creation and save times time_t TimeData; TimeData = WorkDoc->GetCreationTime(); LocalEnvironment::SystemTimeToString(&String, &TimeData); LocalEnvironment::SystemDateToString(&String2, &TimeData); String += _T(" "); String += String2; UpdateStringGadgetValue(_R(IDC_FILEINFO_CREATIONDATE), &String); TimeData = WorkDoc->GetLastSaveTime(); if (TimeData != 0) { LocalEnvironment::SystemTimeToString(&String, &TimeData); LocalEnvironment::SystemDateToString(&String2, &TimeData); String += _T(" "); String += String2; UpdateStringGadgetValue(_R(IDC_FILEINFO_LASTSAVEDATE), &String); } else { String.MakeMsg(_R(IDS_FILEINFO_UNSAVED)); UpdateStringGadgetValue(_R(IDC_FILEINFO_LASTSAVEDATE), &String); } #ifdef STANDALONE EnableGadget(_R(IDC_FILEINFO_COMMENT),FALSE); #endif return TRUE; } /******************************************************************************************* > Node* StartTreeScan(Document* pDoc); Author: Peter_Arnold (Xara Group Ltd) Created: 31th August 1994 Inputs: Pointer to the document to scan. Returns: Pointer to the first node. Purpose: To scan a tree "not depth first". Instead of skipping to the bottom of the tree and scanning back up I want to scan to the bottom and skip back up. Initialises the scan of the document. See also: GetNextTreeNode *******************************************************************************************/ Node* StartTreeScan(Document* pDoc) { if (pDoc == NULL) { ENSURE(FALSE,"NULL document pointer passed to StartTreeScan"); return NULL; } return pDoc->GetFirstNode(); } /******************************************************************************************* > Node* GetNextTreeNode(Node* Current); Author: Peter_Arnold (Xara Group Ltd) Created: 31th August 1994 Inputs: The current node. Returns: Pointer to the next node. Purpose: To scan a tree "not depth first". Instead of skipping to the bottom of the tree and scanning back up I want to scan to the bottom and skip back up. Gets the node after the current one. Returns NULL if no more See also: StartTreeScan, SkipSubTreeScan *******************************************************************************************/ Node* GetNextTreeNode(Node* Current) { if (Current == NULL) { ENSURE(FALSE,"NULL node pointer passed to GetNextTreeNode"); return NULL; } // first try going down one level if (Current->FindFirstChild() != NULL) { return Current->FindFirstChild(); } // now try going right one if (Current->FindNext() != NULL) { return Current->FindNext(); } // if we get this far we need to go up and to the right. Node* Temp = Current->FindParent();; while (Temp != NULL) { if (Temp->FindNext() != NULL) { return Temp->FindNext(); } Temp = Temp->FindParent(); } // no more nodes left in the document return NULL; } /******************************************************************************************* > Node* SkipSubtreeScan(Node* Current); Author: Peter_Arnold (Xara Group Ltd) Created: 31th August 1994 Inputs: The current node. Returns: Pointer to the next node. Purpose: To skip the scan of the children of the current node. The node returned is either a sibling or a parent of the current node. Can return NULL. See also: GetNextTreeNode *******************************************************************************************/ Node* SkipSubtreeScan(Node* Current) { if (Current == NULL) { ENSURE(FALSE,"NULL node pointer passed to SkipSubTreeScan"); return NULL; } if (Current->FindNext() != NULL) { return Current->FindNext(); } // now we need to go up and to the right. Node* Temp = Current->FindParent(); while (Temp != NULL) { if (Temp->FindNext() != NULL) { return Temp->FindNext(); } Temp = Temp->FindParent(); } return NULL; } /******************************************************************************************* > BOOL FileInfo::AddToSortedList(List& ItemList, UINT32 idBitmap, String_64& strItemName, String_256& strDetails) Author: Phil_Martin (Xara Group Ltd) Created: 01/01/2005 Inputs: List Bitmap ID Item name Item details Outputs: - Returns: - Purpose: Create a new item in the list, insertion sorted alphabetically by item name Errors: - SeeAlso: - *******************************************************************************************/ BOOL FileInfo::AddToSortedList(List& ItemList, UINT32 idBitmap, String_64& strItemName, String_256& strDetails) { RefItem* pNewItem = new RefItem(idBitmap, strItemName, strDetails); if (pNewItem == NULL) { ERROR3("AddRefsItem couldn't create Item"); return FALSE; } // Add the item into the list, in a sorted fashion... RefItem *pTheItem = (RefItem*)ItemList.GetHead(); if (pTheItem == NULL) { ItemList.AddTail(pNewItem); return TRUE; } if (pTheItem->strItemName > strItemName) { ItemList.InsertBefore(pTheItem, pNewItem); return TRUE; } while (pTheItem != NULL) { RefItem* pTheNextItem = (RefItem*)ItemList.GetNext(pTheItem); if (pTheNextItem == NULL) { ItemList.InsertAfter(pTheItem, pNewItem); return TRUE; } if (pTheNextItem->strItemName > strItemName) { ItemList.InsertBefore(pTheNextItem, pNewItem); return TRUE; } // Try the next item pTheItem = pTheNextItem; } // Should never get here! ERROR3("Why are we here?"); return FALSE; }