// $Id: plugmngr.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============================ */ // #include "camtypes.h" //#include "app.h" // GetApplication() - in camtypes.h [AUTOMATICALLY REMOVED] #include "plugmngr.h" // main header file #include "plugin.h" // useful plug-in related items #include "fileutil.h" // useful file utilities #include "pshpmngr.h" // PhotoShopHandler #include "bfxmngr.h" // Bfxhandler #include "plugbrws.h" #include "plugop.h" // PlugInOp #include "plugopun.h" // PlugInUndoOp //#include "plugres.h" // _R(IDS_PLUGIN_ONE) #include "progress.h" // Progress //#include "fixmem.h" // CCMalloc CCFree - in camtypes.h [AUTOMATICALLY REMOVED] #include "sgliboil.h" // SGLibOil::AppendSlashIfNotPresent #include "sgrmfile.h" // LibSettings #include "product.h" // PRODUCT_PLUGINS_INIFILE // Only include the freehand plug-ins if required #ifdef FREEHANDPLUGINS #include "xtrahand.h" // Freehand Xtra Plugin Handler #endif // FREEHANDPLUGIN #include "menuitem.h" // MenuItem #include "oilmenus.h" // GetMainMDIMenu #include "menupref.h" // CreateMenuItem #include "pshpop.h" // OPTOKEN_PHOTOSHOP_APPLYLAST #include "registry.h" // SaveRegistryEntries #include "appprefs.h" // OPTOKEN_PLUGSDLG // Place any IMPLEMENT type statements here CC_IMPLEMENT_DYNAMIC(PlugInHandler, ListItem) CC_IMPLEMENT_DYNAMIC(PlugInManager, CCObject) // We want better memory tracking #define new CAM_DEBUG_NEW // declare any statics /******************************************************************************************** Preference: ParseAtStartUp Section: Plug-ins Range: TRUE or FALSE Purpose: If TRUE, then the plug-in pathnames will be searched at start up for plug-ins. If FALSE, then the searching happens the first time any plug-in UI is invoked. SeeAlso: - ********************************************************************************************/ BOOL PlugInManager::m_ParseAtStartUp = TRUE; /************************************************************************************** > PlugInHandler::PlugInHandler() Author: Neville_Humphrys (Xara Group Ltd) Created: 10/12/96 Purpose: Main constructor for the plug-in handler in Camelot. **************************************************************************************/ PlugInHandler::PlugInHandler() { } /************************************************************************************** > PlugInHandler::~PlugInHandler() Author: Neville_Humphrys (Xara Group Ltd) Created: 10/12/96 Purpose: Main destructor for the plug-in handler in Camelot. **************************************************************************************/ PlugInHandler::~PlugInHandler() { } /************************************************************************************** > virtual BOOL PlugInHandler::AddFixedPlugIns() Author: Neville_Humphrys (Xara Group Ltd) Created: 4/3/97 Inputs: - Returns: True if worked, False otherwise Purpose: Add any fixed plug-ins to the list in the plug-in manager and register the op descriptor to the system. By fixed, I mean those which are not file related and hence will be loaded when the specified paths are parsed for plug-ins. This baseclass version does nothing. **************************************************************************************/ BOOL PlugInHandler::AddFixedPlugIns() { return TRUE; } /************************************************************************************** > virtual BOOL PlugInHandler::AddPlugIn(PlugInItem * pPlugIn, CCRuntimeClass* pClass = CC_RUNTIME_CLASS(PlugInOp), pfnGetState gs = PlugInOp::GetState) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/12/96 Inputs: pPlugIn the new PlugInItem to add to the list pClass the operation handling class to use gs the GetState function to use Returns: True if worked, False otherwise Purpose: Add a plug-in to the list in the plug-in manager and register the op descriptor to the system. **************************************************************************************/ BOOL PlugInHandler::AddPlugIn(PlugInItem * pPlugIn, CCRuntimeClass* pClass, pfnGetState gs) { PlugInManager* pManager = GetApplication()->GetPlugInManager(); if (pManager == NULL) return FALSE; if (!pManager->AddPlugIn(pPlugIn)) ERROR2(FALSE,"Failed to register a plug-in with plug-in manager"); // Make up a unique name for the plug in String_32 OpToken = GetUniqueID(); OpToken += pPlugIn->GetPlugInName(); // Register this name as an OpDescriptor to the system so that we can use it // on menus etc. if (!PlugInOp::RegisterOpToken(OpToken, pPlugIn->GetPlugInName(), pClass, gs)) ERROR2(FALSE,"Failed to register OpToken for a plug-in"); // Now see if the family name is registered, if not then register it OpToken = GetUniqueID(); OpToken += pPlugIn->GetFamilyName(); OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OpToken); if (pOpDesc == NULL) { // Register this name as an OpDescriptor to the system so that we can use it // on menus etc. if (!PlugInOp::RegisterOpToken(OpToken, pPlugIn->GetFamilyName(), pClass, gs)) ERROR2(FALSE,"Failed to register OpToken for a plug-in family name"); } return TRUE; } /******************************************************************************************** > BOOL PhotoShopHandler::CreateMainMenuItems(PlugInManager * pManager, MenuItem * pRootMenu, BOOL AddSeparator = FALSE) Author: Neville_Humphrys (Xara Group Ltd) Created: 12/1/97 Inputs: pManager the plug-in manager to get at useful things like the plug-in list pRootMenu The root of the main menu to add the items to AddSeparator True if want a separator added to the last item on the menu Outputs: - Returns: True if the operation completed successfully False if it failed in some way. Purpose: After the plug in list has been sorted alphabetically we must add each item in the list to the main plug-in menu. This is a handler's chance to insert menu options into this menu. This baseclass version does nothing and so needs to be overridden by a handler to do something useful. ********************************************************************************************/ BOOL PlugInHandler::CreateMainMenuItems(PlugInManager * pManager, MenuItem * pRootMenu, BOOL AddSeparator) { ERROR2IF(pManager == NULL || pRootMenu == NULL,FALSE,"CreateMainMenuItems bad parameters!"); // This baseclass version does nothing return TRUE; } /************************************************************************************** **************************************************************************************/ /************************************************************************************** > PlugInManager::PlugInManager() Author: Neville_Humphrys (Xara Group Ltd) Created: 9/12/96 Purpose: Main constructor for the plug-in manager in Camelot. **************************************************************************************/ PlugInManager::PlugInManager() { // Flag that we have not been initialised yet m_Initialised = FALSE; // Default to parsing paths at start up m_ParseAtStartUp = TRUE; // Flag that we have not searched the plug-ins path yet m_SearchedPaths = FALSE; } /************************************************************************************** > PlugInManager::~PlugInManager() Author: Neville_Humphrys (Xara Group Ltd) Created: 9/12/96 Purpose: Main destructor for the plug-in manager in Camelot. **************************************************************************************/ PlugInManager::~PlugInManager() { // Clean out our list of pathnames /* PlugInPath* pPath = (PlugInPath *)Paths.GetHead(); while (pPath != NULL) { delete pBitmap->pBmp; // Try the next pathname in the list pPath = (PlugInPath *)Paths.GetNext(pPath); } */ //Paths.DeleteAll(); // Clean out the list of plug-in handlers that Camelot understands. m_HandlersList.DeleteAll(); // Clean out the list of plug-in items DestroyPlugInsList(); } /************************************************************************************** > BOOL PlugInManager::DestroyPlugInsList() Author: Neville_Humphrys (Xara Group Ltd) Created: 12/12/96 Returns: True if worked ok, False otherwise. Purpose: Destroy the list of plugs that the plug-in manager in Camelot currently has. **************************************************************************************/ BOOL PlugInManager::DestroyPlugInsList() { // We need to write the code to destruct an OpDescriptor and delink it from the // list before we can do this. // We must go through the list of plug-ins and deregister things like the // allocated op-descriptors that we allocated when the plug-in was created. PlugInItem* pPlugIn = (PlugInItem *)m_PlugInsList.GetHead(); String_32 OpToken; String_32 FamilyOpToken; String_32 LastFamilyOpToken; while (pPlugIn != NULL) { OpToken = pPlugIn->GetUniqueID(); FamilyOpToken = OpToken; OpToken += pPlugIn->GetPlugInName(); FamilyOpToken += pPlugIn->GetFamilyName(); // Search for the OpDescriptor OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OpToken); if (pOpDesc != NULL) { OpDescriptor::DelinkDescriptor(pOpDesc); delete pOpDesc; } // If the family optoken changes then this is the time to delete it if (FamilyOpToken != LastFamilyOpToken) { // Search for the OpDescriptor pOpDesc = OpDescriptor::FindOpDescriptor(FamilyOpToken); if (pOpDesc != NULL) { OpDescriptor::DelinkDescriptor(pOpDesc); delete pOpDesc; } } LastFamilyOpToken = FamilyOpToken; // Try the next plug-in in the list pPlugIn = (PlugInItem *)m_PlugInsList.GetNext(pPlugIn); } // Clean out the list of plug-in items m_PlugInsList.DeleteAll(); // Lastly, flag that we have now not parsed all the paths m_SearchedPaths = FALSE; return TRUE; } /************************************************************************************** **************************************************************************************/ #define ADD_HANDLER(Classname) \ { \ /* Create, initialise and install a new plug-in handler */ \ Classname * pHandler = new Classname; \ \ if (pHandler == NULL) return FALSE; \ \ if (!pHandler->Init()) \ { \ /* Error occured - report it and stop trying to initialise filters. */ \ InformError(); \ return TRUE; \ } \ \ m_HandlersList.AddTail(pHandler); \ } /************************************************************************************** > BOOL PlugInManager::Init() Author: Neville_Humphrys (Xara Group Ltd) Created: 9/12/96 Returns: True if initialised ok, False otherwise. Purpose: Main initialisation code for the plug-in manager in Camelot. **************************************************************************************/ BOOL PlugInManager::Init() { #ifndef WEBSTER #ifndef EXCLUDE_BFX //#ifdef NEW_NATIVE_FILTER ADD_HANDLER(BfxHandler); //#endif #endif #endif // Only include the freehand plug-ins if required #ifdef PHOTOSHOPPLUGINS ADD_HANDLER(PhotoShopHandler); #endif // Only include the freehand plug-ins if required #ifdef FREEHANDPLUGINS ADD_HANDLER(XtraHandler); #endif if (!PlugInOp::Init()) return FALSE; // Declare any preferences that we require. if ( Camelot.DeclareSection(TEXT("Plug-ins"), 3) ) { // section declared ok so now define the preference option Camelot.DeclarePref(TEXT("Plug-ins"), TEXT("ParseAtStartUp"), &m_ParseAtStartUp, 0, 1); } // load stored items from preference system BOOL ok = ReadPathNameList(); ok = ok && PlugInOp::RegisterOpToken(OPTOKEN_PLUGINS_MENU, _R(IDS_PLUGINS)); ok = ok && PlugInOp::RegisterOpToken(OPTOKEN_PLUGINS_MANAGER, _R(IDS_PLUGINS)); ok = ok && PlugInOp::RegisterOpToken(OPTOKEN_PLUGINS_PARSING, _R(IDS_PLUGSIN_PARSING)); ok = ok && PlugInOp::RegisterOpToken(OPTOKEN_PLUGINS_PLUGINSMNGR, _R(IDS_PLUGINS_PLUGINSMNGR)); ok = ok && PlugInUndoOp::RegisterOpToken(OPTOKEN_PLUGINS_UNDO_MENU, _R(IDS_PLUGINS)); // Lastly, note that initialised has been called m_Initialised = TRUE; return TRUE; } /******************************************************************************************** > static BOOL PlugInManager::WipePlugInsSettings() Author: Neville_Humphrys (Xara Group Ltd) Created: 28/2/97 Purpose: Wipes the plug-in pathnames list from the ini file or from the registry. SeeAlso: LibSettings::NukeSettings; ********************************************************************************************/ BOOL PlugInManager::WipePlugInsSettings() { #ifdef SAVE_PREFS_TO_REGISTRY // Check if the registry entry is present or not. Look for the our special plugin related // items which should be stored in a 'PlugIns\\Plug-in Pathname List' key. // This is the section and sub-section name that we are going to use String_256 KeySectionName(PRODUCT_REGISTRYKEY_PLUGINS TEXT("\\Plug-in Pathname List")); DeleteRegKey(hAppStateRegKey, KeySectionName); // We must wipe the ini file as well as otherwise when the code checks to // see if the registry settings and then falls back on the ini file if they // are not there, then we wont be using the default settings. #endif // Vape the plug-ins ini file String_256 PlugInsIni(PRODUCT_PLUGINS_INIFILE); LibSettings::NukeSettings(&PlugInsIni); return TRUE; } /******************************************************************************************** > BOOL PlugInManager::ReadPathNameList() Author: Neville_Humphrys (Xara Group Ltd) Created: 17/12/96 Purpose: Reads the plug-in pathnames list in from the ini file. This has to be a new ini file as the main ini file code cannot cope with the concept of sections filled with an arbitrary number of items which need cleaning out when resaving to remove old items no longer required. The code is based on LibSettings::BuildList SeeAlso: CFileList::ReadList(); LibSettings::BuildList; ********************************************************************************************/ BOOL PlugInManager::ReadPathNameList() { #ifdef SAVE_PREFS_TO_REGISTRY // Check if the registry entry is present or not. Look for the our special plugin related // items which should be stored in a 'PlugIns\\Plug-in Pathname List' key. // This is the section and sub-section name that we are going to use String_256 KeySectionName(PRODUCT_REGISTRYKEY_PLUGINS TEXT("\\Plug-in Pathname List")); BOOL EntryPresent = CheckForRegistryEntry(KeySectionName); if (EntryPresent) { LoadRegistryEntries Loader; Loader.StartLoading(&KeySectionName); BOOL AddedItems = FALSE; String_256 FileName; while (Loader.LoadNextEntry(&FileName)) { // only interested in items which contain some data! // If blank then we may parse the entire disc or currently selected directory! if (!FileName.IsEmpty()) { // Add a trailing slash if it hasn't got one SGLibOil::AppendSlashIfNotPresent(&FileName); PathName Path(FileName); m_Paths.AddPathName(Path); // Flag that we have added something AddedItems = TRUE; } } Loader.StopLoading(); } else #endif { // Read in the data from the older ini file that may be kicking around // This is the section name that we are going to use String_256 SectionName(TEXT("Plug-in Pathname List")); // This is the ini file that we are going to be using String_256 PlugInsIni(PRODUCT_PLUGINS_INIFILE); BOOL AddedItems = FALSE; String_256 FileName; CCDiskFile GetEntryFile(1024, FALSE, TRUE); if (LibSettings::GetEntryStart(&GetEntryFile, &PlugInsIni)) { if (LibSettings::SeekToSection(&GetEntryFile, &SectionName)) { while (LibSettings::GetNextLine(&GetEntryFile, &FileName)) { // Add a trailing slash if it hasn't got one SGLibOil::AppendSlashIfNotPresent(&FileName); PathName Path(FileName); m_Paths.AddPathName(Path); // Flag that we have added something AddedItems = TRUE; } } LibSettings::GetEntryFinish(&GetEntryFile); } } // Everything is ok return TRUE; } /******************************************************************************************** > BOOL PlugInManager::WritePathNameList() Author: Neville_Humphrys (Xara Group Ltd) Created: 17/12/96 Purpose: Writes the list of plug-in pathnames to the ini file This has to be a new ini file as the main ini file code cannot cope with the concept of sections filled with an arbitrary number of items which need cleaning out when resaving to remove old items no longer required. SeeAlso: CFileList::WriteList() ********************************************************************************************/ BOOL PlugInManager::WritePathNameList() { #ifdef SAVE_PREFS_TO_REGISTRY BOOL ok = TRUE; // This is the section and sub-section name that we are going to use String_256 SectionName(PRODUCT_REGISTRYKEY_PLUGINS TEXT("\\Plug-in Pathname List")); SaveRegistryEntries Saver; ok = Saver.StartSaving(&SectionName); ERROR3IF(!ok,"PlugInManager::WritePathNameList() couldn't start saving the settings"); // Go through all our stored paths writing them out in the preferences. // DO NOT USE GetHead/GetNext as we would see all the paths, which is more than we should // be seeing. Use the offical GetFirstPath/GetNextPath routines which give us what we // should be seeing, i.e. the user entered paths. PlugInPath* pPath = (PlugInPath *)m_Paths.GetFirstPath(); PathName FileName; String_256 Line; while (pPath != NULL && ok) { // Get the pathname for this entry FileName = pPath->GetPathName(); // Get the string that represents this Line = FileName.GetPath(); // only write out the line if non-blank // If blank then we may parse the entire disc or currently selected directory! if (!Line.IsEmpty()) ok = ok && Saver.SaveNextEntry(&Line); // if !ok then possibly write access denied on in file... or disk full... // So flag that we should stop outputting any more data // Try the next pathname in the list pPath = (PlugInPath *)m_Paths.GetNextPath(pPath); } Saver.StopSaving(); #else // This is the section name that we are going to use String_256 SectionName(TEXT("Plug-in Pathname List")); // This is the ini file that we are going to be using String_256 PlugInsIni(PRODUCT_PLUGINS_INIFILE); LibSettings::StartOutput(&SectionName, &PlugInsIni); LibSettings::AddSection(&SectionName, &PlugInsIni); // Go through all our stored paths writing them out in the preferences. // DO NOT USE GetHead/GetNext as we would see all the paths, which is more than we should // be seeing. Use the offical GetFirstPath/GetNextPath routines which give us what we // should be seeing, i.e. the user entered paths. PlugInPath* pPath = (PlugInPath *)m_Paths.GetFirstPath(); PathName FileName; String_256 Line; BOOL ok = TRUE; while (pPath != NULL && ok) { // Get the pathname for this entry FileName = pPath->GetPathName(); // Get the string that represents this Line = FileName.GetPath(); if (!LibSettings::AddLine(&Line, &PlugInsIni)) { // Possibly write access denied on in file... or disk full... // So flag that we should stop outputting any more data ok = FALSE; } // Try the next pathname in the list pPath = (PlugInPath *)m_Paths.GetNextPath(pPath); } #endif return TRUE; } /************************************************************************************** > BOOL PlugInManager::SearchForPlugIns() Author: Neville_Humphrys (Xara Group Ltd) Created: 17/12/96 Returns: True if parsed ok, False otherwise. Purpose: Starts up the process of parsing all the paths specified to the plug-in manager for plug-ins and stroing information on them in a list. This is called during start up so needs to check the flag to see whether the user has requested this to be done at the start, before actually trying to parse. **************************************************************************************/ BOOL PlugInManager::SearchForPlugIns() { // If the user has requested plug-in parsing at start up then now is the time to do it // Otherwise, delay until the first call if (m_ParseAtStartUp) return ParseAllPaths(); // Otherwise we do the job later return TRUE; } /************************************************************************************** > BOOL PlugInManager::CheckHaveDetailsOnPlugIns() Author: Neville_Humphrys (Xara Group Ltd) Created: 17/12/96 Returns: True if parsed ok, False otherwise. Purpose: Checks to see if the pathnames have been searched for plug-ins. If not then do it now. This should be called by any UI code before they try and put up any UI of plug-ins, e.g. a menu of available plug-ins. If the user requested not to parse pathnames at start up then this is where it happens. **************************************************************************************/ BOOL PlugInManager::CheckHaveDetailsOnPlugIns() { // If we have not already parsed the paths then go and do it now as we need it. if (!m_SearchedPaths) return ParseAllPaths(); // Otherwise we do the job later return TRUE; } /************************************************************************************** > BOOL PlugInManager::ParseAllPaths() Author: Neville_Humphrys (Xara Group Ltd) Created: 9/12/96 Returns: True if parsed ok, False otherwise. Purpose: Starts up the process of parsing all the paths specified to the plug-in manager for plug-ins and storing information on them in a list. Assumes the list is either empty before we are called or the caller has cleared it using **************************************************************************************/ BOOL PlugInManager::ParseAllPaths() { // First, flag that we have parsed all the paths m_SearchedPaths = TRUE; BOOL ParsedOk = TRUE; //#if NEW_NATIVE_FILTER // Now, go and make sure that we have no plug-ins main menu items DeleteMainMenuItems(); //#endif // Start adding the plug-ins into the list // First any ones which are fixed or built in and not file related // Go through each of the handlers asking them to add fixed plug-ins. PlugInHandler* pHandler = (PlugInHandler *)m_HandlersList.GetHead(); while (pHandler != NULL) { pHandler->AddFixedPlugIns(); // Try the next handler in the list pHandler = (PlugInHandler *)m_HandlersList.GetNext(pHandler); } // Now look through all the directories that the user has specified // First remove all hidden items from the list // Put up an hourglass to show we are doing something Progress InitialPathsProgress(_R(IDS_PLUGSIN_PARSING)); m_Paths.RemoveHiddenItems(); // Now go through all the pathnames looking for sub-directories recursively // and add these to the list of items // The items we use MUST only ever see non-hidden paths, as otherwise // we will get very recursive!!!!! PlugInPath* pPath = (PlugInPath *)m_Paths.GetFirstPath(); INT32 FilesCount = 0; while (pPath != NULL) { ParsedOk = ParsedOk && ParsePathNameForDirectories(pPath->GetPathName(), &FilesCount); pPath = (PlugInPath *)m_Paths.GetNextPath(pPath); } // Put up a progress bar to show we are doing something Progress PathsProgress(_R(IDS_PLUGSIN_PARSING), FilesCount); // Go through all our stored paths and check them for plug-ins stored in them. pPath = (PlugInPath *)m_Paths.GetHead(); INT32 Count = 0; PathsProgress.Update(Count); while (pPath != NULL) { ParsedOk = ParsedOk && ParsePathName(pPath->GetPathName(), pPath->GetPathNameID(), &Count, PathsProgress); // Try the next pathname in the list pPath = (PlugInPath *)m_Paths.GetNext(pPath); PathsProgress.Update(Count); } // Sort those plug-ins that we have loaded SortPlugInsAlphabetically(); //#if NEW_NATIVE_FILTER // Now, go and create the plug-ins main menu items required CreateMainMenuItems(); //#endif return ParsedOk; } /************************************************************************************** > BOOL PlugInManager::ParsePathNameForDirectories( const PathName& SearchPath, INT32 * pFilesCount) Author: Neville_Humphrys (Xara Group Ltd) Created: 9/12/96 Inputs: ParsePath the pathname to parse for new plug-ins Outputs: pFilesCount an updated count of the files discovered Returns: True if parsed ok, False otherwise. Purpose: Parse the given path for all directories. If found then add them as hidden items to our list of paths so that the user cannot see them. We do it this way so that we only ever store a PathID with a plug-in record rather than having to store the pathname or sub-directories to the pathname with the plug-in. Note: Must be re-entrant! **************************************************************************************/ BOOL PlugInManager::ParsePathNameForDirectories( const PathName& SearchPath, INT32 * pFilesCount) { PathName File = SearchPath; String_256 SearchDir = SearchPath.GetPath(); // If the path is blank then ignore it otherwise we will search the entire hard drive // or currently selected directory! if (SearchDir.IsEmpty()) return TRUE; SearchDir += "*.*"; TRACEUSER( "Neville", _T("ParsePathNameForDirectories Search path is %s\n"), (TCHAR *)SearchDir); FindFiles Finder; BOOL IsDirectory = FALSE; if (Finder.StartFindingFiles(&SearchDir)) { String_256 LeafName; while (TRUE) { if (!Finder.FindNextFile(&LeafName, &IsDirectory)) break; if (pFilesCount) (*pFilesCount)++; // We have found a file or a directory. // In this case we only want to look for directories if (IsDirectory) { // Do something with the directory "LeafName" TRACEUSER( "Neville", _T("ParsePathNameForDirectories add directory %s\n"), (TCHAR *)LeafName); String_256 NewSearchDir = SearchPath.GetPath(); NewSearchDir += LeafName; // Add a trailing slash if it hasn't got one, which it shouldn't have SGLibOil::AppendSlashIfNotPresent(&NewSearchDir); PathName NewSearchPath(NewSearchDir); // Add the new pathname to the list, but as a hidden one so that // people not in the know do not see them. PlugInPath * pPath = m_Paths.AddPathName(NewSearchPath, TRUE); if (pPath) { // recover the id associated with the path ParsePathNameForDirectories(NewSearchPath, pFilesCount); } } } // Stop the process Finder.StopFindingFiles(); } return TRUE; } /************************************************************************************** > BOOL PlugInManager::ParsePathName( const PathName& SearchPath, const INT32 PathID, INT32 * pFilesCount, const Progress& PathsProgress ) Author: Neville_Humphrys (Xara Group Ltd) Created: 9/12/96 Inputs: ParsePath the pathname to parse for new plug-ins pathID the ID assigned to this path PathsProgress the progress object to call for progress update Outputs: pFilesCount an updated count of the files discovered Returns: True if parsed ok, False otherwise. Purpose: Parse the given path for all files and pass the files of the registered types to the appropriate plug-in handler. The handler should then check to see whether it likes this type of file and if so then create a new plug-in record of the correct type and then place useful details into the record. Finally it should register the new plug-in record with the plug-in manager i.e. this class. The PathID should be stored in the plug-in record so that we do not have to store the full path with all plug-in records. **************************************************************************************/ BOOL PlugInManager::ParsePathName( const PathName& SearchPath, const INT32 PathID, INT32 * pFilesCount, const Progress& PathsProgress ) { PathName File = SearchPath; String_256 SearchDir = SearchPath.GetPath(); // If the path is blank then ignore it otherwise we will search the entire hard drive // or currently selected directory! if (SearchDir.IsEmpty()) return TRUE; // We must set up the operating system current directory so that extra DLLs beside the // plug-ins can be picked up. BOOL ok = FileUtil::SetCurrentDirectory( SearchPath ); SearchDir += "*.*"; TRACEUSER( "Neville", _T("ParsePathName Search path is %s, found:-\n"), (TCHAR *)SearchDir); FindFiles Finder; BOOL IsDirectory = FALSE; if (Finder.StartFindingFiles(&SearchDir)) { String_256 LeafName; while (TRUE) { if (!Finder.FindNextFile(&LeafName, &IsDirectory)) break; if (pFilesCount) (*pFilesCount)++; // Do something with file "LeafName" TRACEUSER( "Neville", _T("ParsePathName parse plug-in file %s\n"), (TCHAR *)LeafName); // We have found a file or a directory. // In this case we only want to look for files if (!IsDirectory) { File.SetFileNameAndType(LeafName); String_32 FileType = File.GetType(); FileType.toLower(); PlugInHandler* pHandler = (PlugInHandler *)m_HandlersList.GetHead(); BOOL Found = FALSE; while (pHandler != NULL && !Found) { String_32 HandlerFileType = pHandler->GetFileTypes(); // If the handler returns a filetype which is null then ignore it // as this generally indicates that it will do its own thing. // Handlers can specify a list of file types by splitting them with commas if (!HandlerFileType.IsEmpty() && (HandlerFileType.Sub(FileType) != -1)) //FileType == HandlerFileType) Found = TRUE; else { // Try the next handler in the list pHandler = (PlugInHandler *)m_HandlersList.GetNext(pHandler); } } // If we have found this filetype in our list of handlers then // ask that handler to parse the file. if (Found && pHandler) { pHandler->ParsePlugIn(File, PathID); } // Update our progress bar for the file just parsed if (pFilesCount) PathsProgress.Update(*pFilesCount); } } // Stop the process Finder.StopFindingFiles(); } return TRUE; } /************************************************************************************** > BOOL PlugInManager::GetPlugInPath( PathName* NewSearchPath ) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/12/96 Inputs: - Outputs: NewSearchPath the pathname to parse for new plug-ins Returns: True if parsed ok, False otherwise. Purpose: Allows the requesting of a pathname to parse plug-ins for from the user. Its pops up a modified form of the stanadard file dialog box set up to browse explicitly for paths rather than files. Used by the plug-ins options tab. **************************************************************************************/ BOOL PlugInManager::GetPlugInPath( PathName* NewSearchPath ) { // Ask out special class to pop up a common file dialog box to the user and then // to return the path that the user has requested back to us. BOOL ok = PlugInsBrowser::GetLibPath(NewSearchPath); return ok; } /************************************************************************************** > BOOL PlugInManager::AddPlugInPath( const PathName& NewSearchPath ) Author: Neville_Humphrys (Xara Group Ltd) Created: 12/12/96 Inputs: NewSearchPath the pathname to add to the list Returns: True if added ok, False otherwise. Purpose: Adds a new pathname to the list of pathnames stored in the plug-in manager. **************************************************************************************/ BOOL PlugInManager::AddPlugInPath( const PathName& NewSearchPath ) { // First check to see if its blank or not. If so then ignore it String_256 SearchDir = NewSearchPath.GetPath(); if (SearchDir.IsEmpty()) { ERROR3("AddPlugInPath asked to add blank path!"); return FALSE; } m_Paths.AddPathName(NewSearchPath); return TRUE; } /************************************************************************************** > BOOL PlugInManager::DeletePlugInPath( const PathName& SearchPath ) Author: Neville_Humphrys (Xara Group Ltd) Created: 12/12/96 Inputs: SearchPath the pathname to delete from the list Returns: True if added ok, False otherwise. Purpose: Deletes a pathname from the list of pathnames stored in the plug-in manager. **************************************************************************************/ BOOL PlugInManager::DeletePlugInPath( const PathName& SearchPath ) { return m_Paths.DeletePathName(SearchPath); } /************************************************************************************** > PlugInPath * PlugInManager::GetFirstPathName() Author: Neville_Humphrys (Xara Group Ltd) Created: 12/12/96 Returns: Pointer to a plug-in pathname in the list. Purpose: Get the first plug-in pathname in the list stored in the plug-in manager. This is just the list of user defined paths and does not include the hidden paths that are stored in the list as well. **************************************************************************************/ PlugInPath * PlugInManager::GetFirstPathName() { return (PlugInPath *)m_Paths.GetFirstPath(); } /************************************************************************************** > PlugInPath * PlugInManager::GetNextPathName(PlugInPath * pPath) Author: Neville_Humphrys (Xara Group Ltd) Created: 12/12/96 Inputs: pPlugIn pointer to the current plug-in in the list Returns: Pointer to a plug-in pathname in the list. Purpose: Get the next plug-in pathname in the list stored in the plug-in manager. This is just the list of user defined paths and does not include the hidden paths that are stored in the list as well. **************************************************************************************/ PlugInPath * PlugInManager::GetNextPathName(PlugInPath * pPath) { return (PlugInPath *)m_Paths.GetNextPath(pPath); } /************************************************************************************** > BOOL PlugInManager::AddPlugIn(PlugInItem * pPlugIn) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/12/96 Returns: True if worked, False otherwise Purpose: Add a plug-in to the list in the plug-in manager and register the op desciptor to the system. **************************************************************************************/ BOOL PlugInManager::AddPlugIn(PlugInItem * pPlugIn) { m_PlugInsList.AddTail(pPlugIn); return TRUE; } /************************************************************************************** > BOOL PlugInManager::RemovePlugIn(PlugInItem * pPlugIn) Author: Richard_Millican (Xara Group Ltd) Created: 15/1/97 Inputs: pPlugIn - Pointer to plugin item Returns: True if worked, False otherwise Purpose: Removes a plug-in from the list in the plug-in manager (if it's there) **************************************************************************************/ BOOL PlugInManager::RemovePlugIn(PlugInItem * pPlugIn) { if(m_PlugInsList.RemoveItem(pPlugIn) == NULL) return FALSE; return TRUE; } /************************************************************************************** > PlugInItem * PlugInManager::GetFirstPlugIn() Author: Neville_Humphrys (Xara Group Ltd) Created: 11/12/96 Returns: Pointer to a plug-in item in the list. Purpose: Get the first plug-in item in the list stored in the plug-in manager. **************************************************************************************/ PlugInItem * PlugInManager::GetFirstPlugIn() { return (PlugInItem *)m_PlugInsList.GetHead(); } /************************************************************************************** > PlugInItem * PlugInManager::GetNextPlugIn(PlugInItem * pPlugIn) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/12/96 Inputs: pPlugIn pointer to the current plug-in in the list Returns: Pointer to a plug-in item in the list. Purpose: Get the next plug-in item in the list stored in the plug-in manager. **************************************************************************************/ PlugInItem * PlugInManager::GetNextPlugIn(PlugInItem * pPlugIn) { return (PlugInItem *)m_PlugInsList.GetNext(pPlugIn); } /************************************************************************************** > PlugInItem * PlugInManager::GetPreviousPlugIn(PlugInItem * pPlugIn) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/12/96 Inputs: pPlugIn pointer to the current plug-in in the list Returns: Pointer to a previous plug-in item in the list. Purpose: Get the previous plug-in item in the list stored in the plug-in manager. **************************************************************************************/ PlugInItem * PlugInManager::GetPreviousPlugIn(PlugInItem * pPlugIn) { return (PlugInItem *)m_PlugInsList.GetPrev(pPlugIn); } /************************************************************************************** > BOOL PlugInManager::GetPlugInPathname(INT32 PathNameID, String_256 * pPathName) Author: Neville_Humphrys (Xara Group Ltd) Created: 11/12/96 Inputs: PathNameID id of the pathname to search for pPathName pointer to a string to fill in with the pathname pPlugIn pointer to the current plug-in in the list Returns: True if worked ok, False otherwise. Purpose: Converts a pathanme id which is stored with each plug-in into the real pathname that it corresponds to by searching the pathname list in the plug-in manager. **************************************************************************************/ BOOL PlugInManager::GetPlugInPathname(INT32 PathNameID, String_256 * pPathName) { ERROR2IF(pPathName == NULL,FALSE,"PlugInManager::GetPlugInPathname null pPath"); // Make the string empty pPathName->Empty(); // Go through all our stored paths and check them for plug-ins stored in them. PlugInPath* pPath = (PlugInPath *)m_Paths.GetHead(); while (pPath != NULL) { if (pPath->GetPathNameID() == PathNameID) { *pPathName = pPath->GetPathNameAsString(); return TRUE; } // Try the next pathname in the list pPath = (PlugInPath *)m_Paths.GetNext(pPath); } // Nothing found so return this to the user return FALSE; } /******************************************************************************************** > BOOL PlugInManager::SortPlugInsAlphabetically() Author: Neville_Humphrys (Xara Group Ltd) Created: 16/12/96 Inputs: - Outputs: - Returns: True if the operation completed successfully False if it failed in some way. Purpose: Sorts the list of plugs-in alphabetically Borrowed code from SuperGallery::ApplySortNow as we need a much simpler version. Errors: - SeeAlso: ImportedColours::SortColoursByEntryNumber(); SuperGallery::ApplySortNow ********************************************************************************************/ BOOL PlugInManager::SortPlugInsAlphabetically() { INT32 NumItems = 0; // Count the number of items we have to sort PlugInItem * pPlugIn = GetFirstPlugIn(); while (pPlugIn != NULL) { NumItems ++; pPlugIn = GetNextPlugIn(pPlugIn); } // Start progress indicators, with a percentage based upon the number of items. // We will update twice for each group (after qsort and shuffle-items stages) Progress SortProgress(_R(IDS_PLUGSIN_SORTING), NumItems * 2, FALSE); INT32 NumItemsToSort = 0; if (NumItems > 1) { // Get memory for an array of pointers to these items PlugInItem **SortArray = (PlugInItem **)CCMalloc(NumItems * sizeof(PlugInItem *)); if (SortArray == NULL) return FALSE; // Fill in the array with pointers to display items to sort INT32 i = 0; PlugInItem * pPlugIn = GetFirstPlugIn(); while (pPlugIn != NULL) { SortArray[i++] = pPlugIn; pPlugIn = GetNextPlugIn(pPlugIn); } // Sort the array of pointers qsort(SortArray, NumItems, sizeof(PlugInItem *), PlugInManager::SortComparator); NumItemsToSort += NumItems; // Update percentage complete for the number of items processed SortProgress.Update(NumItemsToSort); // Now, take the sorted array, and rearrange the items to be in that order // Special case the first item PlugInItem *pPrevPlugIn = GetPreviousPlugIn(SortArray[0]); if (pPrevPlugIn != NULL) { m_PlugInsList.RemoveItem(SortArray[0]); m_PlugInsList.InsertBefore(SortArray[1], SortArray[0]); } // Then whip through the rest of the items for (i = 1; i < NumItems; i++) { pPrevPlugIn = GetPreviousPlugIn(SortArray[i]); if (pPrevPlugIn != SortArray[i-1]) { m_PlugInsList.RemoveItem(SortArray[i]); m_PlugInsList.InsertAfter(SortArray[i-1], SortArray[i]); } } // Free our temporary workspace CCFree(SortArray); } // End the progress bar that we started //EndSlowJob(); // We seem to have sorted the items ok return TRUE; } /******************************************************************************************** > static INT32 __cdecl PlugInManager::SortComparator(const void *Item1, const void *Item2) Author: Neville_Humphrys (Xara Group Ltd) Created: 31/5/96 Inputs: Item1, Item2 - the items to be compared Returns: negative (I am lesser), 0 (we are equal), or positive (I am greater) result of comparing the items with the EntryNumber stored in each item in the loaded colour list. Purpose: 'qsort' comparator function, used when quicksorting the loaded colour list SeeAlso: PlugInManager::SortPlugInsAlphabetically(); ImportedColours::SortColoursByEntryNumber(); SuperGallery::SortComparator; SuperGallery::ApplySortNow; ********************************************************************************************/ INT32 __cdecl PlugInManager::SortComparator(const void *Item1, const void *Item2) { // if (Item1 == NULL || Item2 == NULL) // return 0; PlugInItem *pItem1 = *((PlugInItem **)Item1); PlugInItem *pItem2 = *((PlugInItem **)Item2); if (pItem1 == NULL || pItem2 == NULL) { ERROR3("PlugIn::SortComparator bad pointers!"); return 0; } INT32 Result = 0; // Sort on family name as the highest priority if (pItem1->GetFamilyName() < pItem2->GetFamilyName()) return(-1); if ((pItem1->GetFamilyName() == pItem2->GetFamilyName()) && (pItem1->GetPlugInName() < pItem2->GetPlugInName()) ) return(-1); if ((pItem1->GetFamilyName() == pItem2->GetFamilyName()) && (pItem1->GetPlugInName() == pItem2->GetPlugInName()) ) return 0; // Must be greater than return 1; } /******************************************************************************************** > MenuItem * PlugInManager::FindPlugInMainMenuItem() Author: Neville_Humphrys (Xara Group Ltd) & Re-writen by sjk 2/8/00 so it doesn't have to be a top level menu! Created: 20/1/97 Inputs: - Outputs: - Returns: Pointer to the plug-in main menu item if the operation completed successfully NULL if it failed in some way. Purpose: Finds the main plug-in menu item and returns a pointer to it. ********************************************************************************************/ MenuItem * PlugInManager::FindPlugInMainMenuItem(MenuItem * pMainMenu) { if (pMainMenu == NULL) pMainMenu = GetMainMDIMenu(); MenuItem * pMenu = pMainMenu->GetFirstMenuItem(); String_256 PlugInMenu(OPTOKEN_PLUGINS_UNDO_MENU); String_32 Desc; while (pMenu) { MenuItem * pSub = pMenu->GetFirstMenuItem(); if (pSub) { // check sub menu pSub = FindPlugInMainMenuItem(pMenu); } // Get the OpToken for the current menu item or returned menu item String_32 * pDesc = pSub ? pSub->GetOpToken() : pMenu->GetOpToken(); if (pDesc) Desc = *pDesc; else Desc.Empty(); // If the OpTokens match then it is the one that we desire if (Desc == PlugInMenu) return pSub ? pSub : pMenu; // Go to the next main menu item in the list pMenu = pMainMenu->GetNextMenuItem(pMenu); } return NULL; } /******************************************************************************************** > BOOL PlugInManager::DeleteMainMenuItems() Author: Neville_Humphrys (Xara Group Ltd) Created: 20/1/97 Inputs: - Outputs: - Returns: True if the operation completed successfully False if it failed in some way. Purpose: Before the pathnames are parsed, we must clear out the main menu items of all the current plug-ins. ********************************************************************************************/ BOOL PlugInManager::DeleteMainMenuItems() { //#if NEW_NATIVE_FILTER // Search the main menu items until we find the plug-ins one MenuItem * pRootMenu = FindPlugInMainMenuItem(); if (pRootMenu == NULL) return FALSE; // Completely destroy this menu BOOL ok = DestroyCamMenu(pRootMenu); // We must add back an item so that the menu is not empty otherwise // all hell will break loose if its left in this state!!!! // Create a menu item for the apply last item // MenuItem * pApplyLastItem = CreateMenuItem(OPTOKEN_PLUGINS_PARSING, pRootMenu->GetMenuId(), FALSE); // If created ok then add this to the main plug-in's menu // if (pApplyLastItem) // pRootMenu->AddMenuItem(pApplyLastItem); // Just in case anything goes wrong between here and adding the new plug-ins back in // we must make sure that the plug-ins win menu is updated to mirror the kernel // menu structure that we have just blatted BOOL update = UpdatePlugInsWinMenu(pRootMenu); //#endif return TRUE; } /******************************************************************************************** > BOOL PlugInManager::CreateMainMenuItems() Author: Neville_Humphrys (Xara Group Ltd) Created: 17/1/97 Inputs: - Outputs: - Returns: True if the operation completed successfully False if it failed in some way. Purpose: After the plug in list has been sorted alphabetically we must add each item in the list to the main plug-in menu. ********************************************************************************************/ BOOL PlugInManager::CreateMainMenuItems() { /* //#if NEW_NATIVE_FILTER // Search the main menu items until we find the plug-ins one MenuItem * pRootMenu = FindPlugInMainMenuItem(); if (pRootMenu == NULL) return FALSE; // // Create the plug-ins manager menu item... // MenuItem * pPlugDlgMngr = CreateMenuItem(OPTOKEN_PLUGSDLG, pRootMenu->GetMenuId(), TRUE); // // If created ok then add this to the main plug-in's menu // if (pPlugDlgMngr) // pRootMenu->AddMenuItem(pPlugDlgMngr); // // Create a menu item for the apply last item MenuItem * pApplyLastItem = CreateMenuItem(OPTOKEN_PHOTOSHOP_APPLYLAST, pRootMenu->GetMenuId(), FALSE); // If created ok then add this to the main plug-in's menu if (pApplyLastItem) pRootMenu->AddMenuItem(pApplyLastItem); // // Go through all the handlers asking them to add in sections to the main menu PlugInHandler* pHandler = (PlugInHandler *)m_HandlersList.GetHead(); PlugInHandler* pNextHandler = NULL; BOOL AddedOk = TRUE; BOOL AddSeparator = TRUE; while (pHandler != NULL) { // Try the next handler in the list pNextHandler = (PlugInHandler *)m_HandlersList.GetNext(pHandler); // If there is a next handler then we must add a separator to the // end of the list. // This does assume that only one handler will not want to add items to the end. // but this is good enough for now if (pNextHandler && pNextHandler->GoingToAddMainMenuItems()) AddSeparator = TRUE; else AddSeparator = FALSE; // Ask the handler to add its required section of the menu to the list AddedOk = pHandler->CreateMainMenuItems(this, pRootMenu, AddSeparator); // Try the next handler in the list pHandler = pNextHandler; } // Make sure that the plug-ins win menu is updated to mirror the kernel // menu structure that we have just created BOOL update = UpdatePlugInsWinMenu(pRootMenu); */ //#endif return TRUE; }