00001 // $Id: menupref.cpp 1550 2006-07-26 12:35:47Z luke $ 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 // MenuPref.cpp - This module is responsible for parsing a menu script and generating 00100 // a set of Camelot Menus. 00101 00102 00103 #include "camtypes.h" 00104 #include "menuitem.h" 00105 #include "menucmds.h" 00106 #include "menupref.h" 00107 #include "menuops.h" 00108 //#include "opdesc.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00111 //#include "mario.h" 00112 #include "oilfiles.h" 00113 00114 DECLARE_SOURCE("$Revision: 1550 $"); 00115 00116 // We want better memory tracking 00117 #define new CAM_DEBUG_NEW 00118 00119 MenuItem* CreateMenuItem(TCHAR *OpToken, UINT32 ParentId, BOOL Separator); 00120 00121 UINT32 WindowMenuID; 00122 00123 00124 /******************************************************************************************** 00125 00126 > inline void ClearArray(TCHAR buffer[], INT32 size); 00127 00128 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00129 Created: 6/8/93 00130 Inputs: Char Array 00131 Integer - Array Size 00132 Outputs: - 00133 Returns: - 00134 Purpose: Initialises a Character Array with Nulls 00135 Errors: - 00136 00137 ********************************************************************************************/ 00138 00139 inline void ClearArray(TCHAR buffer[], INT32 size) 00140 { 00141 ::memset(buffer, 0, size * sizeof(buffer[0])); 00142 } 00143 00144 00145 00146 /******************************************************************************************** 00147 00148 > MenuItem *GetMenuPreferences(UINT32 ResourceID) 00149 00150 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00151 Created: 6/8/93 00152 Inputs: ResourceID representing the menu resource to be loaded. 00153 Outputs: - 00154 Returns: A MenuItem representing the default Menu that was parsed in or NULL if failed 00155 (SetError will be called) 00156 Purpose: Parses a Menu Script representing the Camelot Default Menus. 00157 Errors: - 00158 SeeAlse: GetToken(); 00159 SeeAlso: GetKeyword(); 00160 SeeAlso: GetSeparator(); 00161 00162 ********************************************************************************************/ 00163 00164 MenuItem *GetMenuPreferences(UINT32 ResourceID) 00165 { 00166 // Keyword Buffer 00167 const INT32 keywordSize = 10; 00168 TCHAR keyword[keywordSize]; 00169 00170 // Token Buffer 00171 const INT32 TokenSize = 30; 00172 TCHAR OpToken[TokenSize]; 00173 00174 // Lexical Tokens 00175 const String_256 menu_sym = "MENU"; 00176 const String_256 submenu_sym = "SUBMENU"; 00177 const String_256 menuitem_sym = "MENUITEM"; 00178 const String_256 end_sym = "END"; 00179 const String_256 separator_sym = "SEPARATOR"; 00180 00181 CCResTextFile MenuScript; // Resource File 00182 00183 // Open Resource File 00184 MenuScript.open(ResourceID, _R(IDT_CAM_MENU_RES)); 00185 00186 // Stack of all the Menus and SubMenus currently in Scope! 00187 List MenuStack; 00188 00189 MenuItem* pCurMenu = NULL; // Menu Currently in Scope 00190 00191 MenuItem* pMenu = NULL; 00192 MenuItem* pSubMenu; 00193 MenuItem* pMenuItem; 00194 00195 while ((MenuScript.isOpen()) && (!MenuScript.eof())) 00196 { 00197 ClearArray(keyword, keywordSize); 00198 00199 //Get The Keyword 00200 if (GetKeyword(&MenuScript, keyword, keywordSize)) 00201 { 00202 // MENU reserved word 00203 if (menu_sym == keyword) 00204 { 00205 ERRORIF((!GetToken(&MenuScript, OpToken, TokenSize)), 00206 _R(IDE_SYNTAX_ERROR), 00207 NULL); 00208 00209 pMenu = new MenuItem(OpToken); 00210 00211 if (pMenu==NULL) 00212 { 00213 TRACEALL( _T("GetMenuPrefs: failed to allocate MenuItem")); 00214 break; // willeventually return NULL 00215 } 00216 00217 pCurMenu = pMenu; 00218 } 00219 // SUBMENU reserved word 00220 else if (submenu_sym == keyword) 00221 { 00222 ERRORIF((!GetToken(&MenuScript, OpToken, TokenSize)), 00223 _R(IDE_SYNTAX_ERROR), 00224 NULL); 00225 00226 TRACEUSER( "luke", _T("SUBMENU \"%s\" \"%s\"\n"), OpToken, OPTOKEN_DEBUG_MENU ); 00227 00228 #if !defined(_DEBUG) 00229 // Remove DEBUG menu 00230 if( 0 == camStrcmp( OpToken, OPTOKEN_DEBUG_MENU ) ) 00231 { 00232 TRACEUSER( "luke", _T(">-SUBMENU %s\n"), OPTOKEN_DEBUG_MENU ); 00233 MenuStack.AddHead(pCurMenu); //Push Current Menu onto stack 00234 pCurMenu = NULL; 00235 continue; 00236 } 00237 #endif 00238 00239 pSubMenu = CreateMenuItem( OpToken, 00240 pCurMenu->GetMenuId(), 00241 GetSeparator( &MenuScript, 00242 separator_sym, 00243 keyword, 00244 keywordSize) 00245 ); 00246 00247 // stop now if run out of memory 00248 if (pSubMenu==NULL) 00249 break; 00250 00251 // Get the ID for the Window Menu 00252 if (String(OpToken) == String(OPTOKEN_WINDOW_MENU)) 00253 //MenuItem ID must be first sub element of menu because in windows 00254 //menus do not have IDs 00255 WindowMenuID = ((pSubMenu->GetMenuId()) + 1); 00256 00257 pCurMenu->AddMenuItem(pSubMenu); 00258 MenuStack.AddHead(pCurMenu); //Push Current Menu onto stack 00259 pCurMenu = pSubMenu; 00260 } 00261 // MENUITEM reserved word 00262 else if (menuitem_sym == keyword) 00263 { 00264 ERRORIF((!GetToken(&MenuScript, OpToken, TokenSize)), 00265 _R(IDE_SYNTAX_ERROR), 00266 NULL); 00267 00268 #if !defined(_DEBUG) 00269 // Don't add menu itemns if parent not wanted 00270 if( NULL == pCurMenu ) 00271 continue; 00272 #endif 00273 00274 pMenuItem = CreateMenuItem( OpToken, 00275 pCurMenu->GetMenuId(), 00276 GetSeparator( &MenuScript, 00277 separator_sym, 00278 keyword, 00279 keywordSize) 00280 ); 00281 00282 if (pMenuItem != NULL) 00283 pCurMenu->AddMenuItem(pMenuItem); 00284 else 00285 break; 00286 00287 } 00288 // END reserved word 00289 else if (end_sym == keyword) 00290 { // Pop Menu from stack 00291 pCurMenu = (MenuItem*) MenuStack.RemoveHead(); 00292 // WEBSTER - markn 22/1/97 00293 // Stops circular menu lists being generated when the last main menu item 00294 // contains a sub menu (thank you mario) 00295 if (pCurMenu != NULL) 00296 pCurMenu->ClearPointers(); 00297 } 00298 } 00299 00300 } 00301 00302 MenuScript.close(); 00303 00304 return pMenu; 00305 } 00306 00307 /******************************************************************************************** 00308 00309 > MenuItem *CreateMenuItem(TCHAR *OpToken, UINT32 ParentId, BOOL Separator) 00310 00311 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00312 Created: 29/9/93 00313 Inputs: OpToken used to get the appropriate operation 00314 Parent Identifier 00315 Separator Boolean 00316 Returns: MenuItem if created ok else NULL 00317 Purpose: Creates a MenuItem given an Optoken. 00318 00319 ********************************************************************************************/ 00320 00321 MenuItem *CreateMenuItem(TCHAR *OpToken, UINT32 ParentId, BOOL Separator) 00322 { 00323 OpDescriptor *Operation = OpDescriptor::FindOpDescriptor(OpToken); 00324 00325 PORTNOTE( "other", "Use DO_NOTHING op for menuitem, if optoken not found" ); 00326 #if defined(EXCLUDE_FROM_XARALX) 00327 if( NULL == Operation ) 00328 Operation = OpDescriptor::FindOpDescriptor( OPTOKEN_DO_NOTHING ); 00329 #endif 00330 00331 if (!Operation) 00332 { 00333 String_256 ErrorMsg(_R(IDE_OPNOTFOUND)); 00334 ErrorMsg += OpToken; 00335 00336 Error::SetError(_R(IDE_OPNOTFOUND), ErrorMsg, 0); 00337 InformError(); 00338 00339 return NULL; 00340 } 00341 else 00342 { 00343 MenuItem *pMenuItem; 00344 00345 // Create an instance of a MenuItem 00346 pMenuItem = new MenuItem( ParentId, 00347 Operation, 00348 Separator 00349 ); 00350 00351 ERROR3IF( pMenuItem==NULL, "CreateMenuItem failed" ); 00352 00353 return pMenuItem; 00354 } 00355 } 00356 00357 /******************************************************************************************** 00358 00359 > BOOL GetKeyword(CCResTextFile *pResScript, TCHAR keyword[], INT32 size) 00360 00361 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00362 Created: 6/8/93 00363 Inputs: Input Stream - Menu Script 00364 Integer - Maximum size of keyword 00365 Outputs: Char Array - The Keyword 00366 Returns: TRUE if Keyword is found 00367 FALSE otherwize 00368 Purpose: Parses a Menu Script Keyword. 00369 Errors: - 00370 00371 ********************************************************************************************/ 00372 00373 BOOL GetKeyword(CCResTextFile *pResScript, TCHAR keyword[], INT32 size) 00374 { 00375 // Get Keyword 00376 TCHAR ch; 00377 INT32 i = 0; 00378 00379 ClearArray(keyword, size); 00380 00381 pResScript->read(ch); 00382 00383 // if not a keyword return false! 00384 if (!String::IsAlpha(ch) && (!pResScript->eof())) 00385 return FALSE; 00386 00387 while (String::IsAlpha(ch) && !pResScript->eof() && i < size) 00388 { 00389 keyword[i++] = ch; 00390 pResScript->read(ch); 00391 } 00392 00393 if (!pResScript->eof()) 00394 return TRUE; 00395 else 00396 { 00397 // TRACEUSER( "JustinF", _T("Menu GetKeyword() - read %s\n"), keyword); 00398 return FALSE; 00399 } 00400 } 00401 00402 /******************************************************************************************** 00403 00404 > BOOL GetToken(CCResTextFile *pMenuScript, TCHAR OpToken[], INT32 TokenSize) 00405 00406 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00407 Created: 6/8/93 00408 Inputs: Input Stream - Menu Script 00409 Integer - Maximum size of Token 00410 Outputs: Char Array - The Token 00411 Returns: TRUE if Token is found 00412 FALSE otherwize 00413 Purpose: Parses a Menu Script Token. 00414 Errors: - 00415 00416 ********************************************************************************************/ 00417 00418 BOOL GetToken(CCResTextFile *pMenuScript, TCHAR OpToken[], INT32 TokenSize) 00419 { 00420 // Get Keyword 00421 TCHAR ch; 00422 INT32 i = 0; 00423 00424 ClearArray(OpToken, TokenSize); 00425 00426 //Go back one place and reread last character. 00427 pMenuScript->seek((pMenuScript->tell() - 1)); 00428 pMenuScript->read(ch); 00429 00430 while (StringBase::IsSpace(ch) && !pMenuScript->eof()) 00431 pMenuScript->read(ch); 00432 00433 if (ch == TEXT('"')) 00434 pMenuScript->read(ch); 00435 else 00436 { 00437 // TRACEUSER( "JustinF", _T("Menu GetToken() - no opening \"\n")); 00438 pMenuScript->close(); 00439 return FALSE; 00440 } 00441 00442 while ((String::IsAlphaNumeric(ch) || (ch == _T('_'))) && 00443 ch != TEXT('"') && 00444 !pMenuScript->eof() && 00445 i < TokenSize) 00446 { 00447 OpToken[i++] = ch; 00448 pMenuScript->read(ch); 00449 } 00450 00451 if (ch == TEXT('"') && !pMenuScript->eof()) 00452 return TRUE; 00453 else 00454 { 00455 // TRACEUSER( "JustinF", _T("Menu GetToken() - read %s\n"), OpToken); 00456 pMenuScript->close(); 00457 return FALSE; 00458 } 00459 } 00460 00461 /******************************************************************************************** 00462 00463 > BOOL GetSeparator( CCResTextFile *pMenuScript, 00464 const String& separator_sym, 00465 TCHAR SepKeyword[], 00466 INT32 size) 00467 00468 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00469 Created: 6/8/93 00470 Inputs: Input Stream - Menu Script 00471 constant String - Separator Symbol 00472 Char Array - Keyword Array 00473 Integer - size of Symbol 00474 Outputs: - 00475 Returns: TRUE if Separator is found 00476 FALSE otherwize 00477 Purpose: Parses a Menu Script Menu Separator Token. 00478 Errors: - 00479 00480 ********************************************************************************************/ 00481 00482 BOOL GetSeparator( CCResTextFile *pMenuScript, 00483 const String& separator_sym, 00484 TCHAR SepKeyword[], 00485 INT32 size) 00486 { 00487 // Get Keyword 00488 TCHAR ch; 00489 INT32 i = 0; 00490 00491 ClearArray(SepKeyword, size); 00492 00493 //Go back one place and reread last character. 00494 pMenuScript->seek((pMenuScript->tell() - 1)); 00495 pMenuScript->read(ch); 00496 00497 //Find First Alpha Numeric Character 00498 while(!String::IsAlpha(ch) && (!pMenuScript->eof()) && (ch != '\n')) 00499 pMenuScript->read(ch); 00500 00501 //Read in the keyword until not Alpha Numeric 00502 while (String::IsAlpha(ch) && (!pMenuScript->eof()) && (i < size)) 00503 { 00504 SepKeyword[i++] = ch; 00505 pMenuScript->read(ch); 00506 } 00507 00508 if (separator_sym == SepKeyword) 00509 return TRUE; 00510 else 00511 { 00512 // TRACEUSER( "JustinF", _T("Menu GetSeparator() - read %s\n"), SepKeyword); 00513 return FALSE; 00514 } 00515 }