camelot.cpp

Go to the documentation of this file.
00001 // $Id: camelot.cpp 1771 2007-06-17 20:14:43Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 /***************************************************************************************************************************/
00099 //
00100 // camelot.cpp - main application class derived from wxApp
00101 //
00102 /***************************************************************************************************************************/
00103 
00104 #include "camtypes.h"
00105 
00106 #include "camdoc.h"
00107 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 #include "camview.h"
00109 #include "camframe.h"
00110 //#include "Res/UKEnglish/stringtbl.h"
00111 #include "kernel.h"
00112 #include "grndrgn.h"
00113 #include "oilmenus.h"
00114 
00115 #if !defined(__WXMSW__)
00116 #include "gdraw.h"
00117 #endif
00118 
00119 #include "cversion.h"
00120 #include "camelot.h"
00121 #include "camdoctp.h"
00122 
00123 #include "keypress.h"
00124 #include "ccdc.h"
00125 #include "camprofile.h"
00126 #include "dlgevt.h"
00127 #include "cartprov.h"
00128 #include "ctrllist.h"
00129 #include "cartctl.h"
00130 #include "xmlutils.h"
00131 #include "camplatform.h"
00132 #include "filedlgs.h"
00133 #include "progress.h"
00134 #include "prdlgctl.h"
00135 #include "prncamvw.h"
00136 #include "gbrush.h"
00137 #include "selmedia.h"
00138 #include "filedlgs.h"
00139 #include "rendwnd.h"
00140 
00141 #include "camprocess.h"
00142 
00143 //
00144 // Define FILELIST for recent file list on file menu.
00145 // Note that this currently seems to be rather unreliable.
00146 //
00147 //#if defined(_DEBUG)
00148 //#define FILELIST
00149 //#endif
00150 
00151 //
00152 // Define XARA_MENUGEN to use Xtreme style menu creation.
00153 // Note that this currently doesn't have full functionality
00154 // but it's getting there
00155 //#if defined(_DEBUG)
00156 #define XARA_MENUGEN
00157 //#endif
00158 
00159 BOOL CCamApp::InInitOrDeInit = TRUE;
00160 IMPLEMENT_DYNAMIC_CLASS( wxWindowDeletionWatcher, wxObject);
00161 WindowToWindowDeletionWatcher * wxWindowDeletionWatcher::s_UndeletedWindowHash = NULL;
00162 
00163 /********************************************************************************************
00164 
00165     Preference: MainWndMax
00166     Section:    Windows
00167     Range:      0 (FALSE) or 1 (TRUE)
00168     Purpose:    If non-zero then main window defaults to maximized, else normal position.
00169                 This default will be overridden if the user explicitly asked for a mode
00170                 when starting the app (e.g. minimized). If the user exits while maximized,
00171                 the flag will be set ready for next time.
00172 
00173 ********************************************************************************************/
00174 BOOL CCamApp::MainWndMaximized = FALSE;
00175 
00176 
00177 /********************************************************************************************
00178 
00179     Preference: MainWndMin
00180     Section:    Windows
00181     Range:      0 (FALSE) or 1 (TRUE)
00182     Purpose:    If non-zero then main window defaults to minimized, else normal position.
00183                 This default will be overridden if the user explicitly asked for a mode
00184                 when starting the app (e.g. minimized). If the user exits while minimized,
00185                 the flag will be set ready for next time.
00186 
00187 ********************************************************************************************/
00188 BOOL CCamApp::MainWndMinimized = FALSE;
00189 
00190 
00191 /********************************************************************************************
00192 
00193     Preference: MainWndPos
00194     Section:    Windows
00195     Range:      Six numbers, separated with spaces, which are x y w h sx sy
00196     Purpose:    Remembers users last 'normal' window position for them. Also remembers the
00197                 screen size so can be scaled if next time runs in different screen mode.
00198 
00199 ********************************************************************************************/
00200 String_256 CCamApp::MainWndPosString;
00201 
00202 
00203 /********************************************************************************************
00204 
00205     Preference: FirstRun
00206     Section:    Preferences
00207     Range:      0 (FALSE) or 1 (TRUE)
00208     Purpose:    If 1 then this is the first time this application has been run with
00209                 this set of preferences
00210                 If 0 then it has been run before
00211 
00212 ********************************************************************************************/
00213 BOOL CCamApp::bFirstRun = TRUE;
00214 
00215 
00216 /***************************************************************************************************************************/
00217 //
00218 // Timer used for background redraw.
00219 // For now we have gone back to using the idle system for redraw as it does seem to work
00220 // The background redraw may be changed to use a timer or some other method
00221 //
00222 
00223 #define CAM_TIMER_ID         42
00224 #define CAM_TIMER_FREQUENCY 100
00225 
00226 /***************************************************************************************************************************/
00227 
00228 IMPLEMENT_APP( CCamApp )
00229 BEGIN_EVENT_TABLE( CCamApp, wxApp )
00230     EVT_IDLE( CCamApp::OnIdle )
00231 //  EVT_TIMER( CAM_TIMER_ID, CCamApp::OnTimer )
00232 END_EVENT_TABLE()
00233 
00234 DialogManager           CCamApp::m_DlgMgr;
00235 bool                    CCamApp::s_bIsDisabled = false; // Initially system is not disabled.
00236 wxString                CCamApp::m_strResourcePath;
00237 String_256              CCamApp::m_strResourceDirPath;
00238 String_256              CCamApp::m_strResourceDirPathOverride;
00239 String_256              CCamApp::m_strMediaApplication;
00240 
00241 /***************************************************************************************************************************/
00242 
00243 CCamApp::CCamApp()
00244 {
00245 }
00246 
00247 /*********************************************************************************************
00248 >   int TYPENOTE: Correct CCamApp::FilterEvent( wxEvent& event )
00249 
00250     Author:     Luke_Hart (Xara Group Ltd) <LukeH@xara.com>
00251     Created:    09/05/06
00252     Inputs:     A reference to the event to filter
00253     Outputs:    -
00254     Returns:    -
00255     Purpose:    This function is used to collect the key press information for handling by
00256                 applictaion. It passes event unmolested for controls that are allowed focus and
00257                 controls within modal dialogs. It also has code to make sure that key events
00258                 that are passed on aren't checked again, based on the event timestamp. All other 
00259                 keys are passed into application keypress handling code.
00260     Errors:     -
00261     Scope:      Protected
00262     SeeAlso:    The focus handling document
00263 
00264 **********************************************************************************************/ 
00265 
00266 int /*TYPENOTE: Correct*/ CCamApp::FilterEvent( wxEvent& event )
00267 {
00268     static /*TYPENOTE: Correct*/ long   lLastTimeStamp = 0;
00269 
00270     wxObject* pEventObject = event.GetEventObject();
00271 
00272     if (( event.GetEventType() == wxEVT_DESTROY ) && pEventObject->IsKindOf(CLASSINFO(wxWindow)))
00273     {
00274         // Register window destruction
00275         wxWindowDeletionWatcher::RegisterWindowDeletion((wxWindow *)pEventObject);
00276     }
00277 
00278     if (PrintMonitor::IsPrintingNow())
00279     {
00280         // Disable processing of paint messages for various controls which may use GDraw or GBrush to paint, as this
00281         // appears to upset printing
00282         if (event.IsKindOf(CLASSINFO(wxPaintEvent)))
00283         {
00284             if (!pEventObject->IsKindOf(CLASSINFO(wxCamArtControl)))
00285             {   
00286                 // TRACEUSER("amb", _T("CCamApp::FilterEvent caught paint for %s"), pEventObject->GetClassInfo()->GetClassName());
00287                 return false;
00288             }
00289         }
00290     }
00291 
00292     if( event.GetEventType() == wxEVT_ACTIVATE )
00293     {
00294         TRACEUSER("luke", _T("CCamApp::FilterEvent activate to %s"), pEventObject->GetClassInfo()->GetClassName());
00295 
00296         if( pEventObject->IsKindOf( CLASSINFO(wxAuiFloatingFrame) ) )
00297         {
00298             wxClassInfo* pClassInfo = pEventObject->GetClassInfo();
00299             while( NULL != pClassInfo )
00300             {
00301                 TRACEUSER( "luke", _T("Class = %s"), (PCTSTR)pClassInfo->GetClassName() );
00302 
00303                 const wxChar* pszBaseClass = pClassInfo->GetBaseClassName1();
00304                 pClassInfo = NULL == pszBaseClass ? NULL : wxClassInfo::FindClass( pszBaseClass );
00305             }
00306             TRACEUSER( "luke", _T("Parent = %x, %x"), ((wxWindow*)pEventObject)->GetParent(), m_pMainFrame );
00307             TRACEUSER( "luke", _T("Active = %x"), ((wxTopLevelWindow*)pEventObject)->IsActive() );
00308 
00309             GiveActiveCanvasFocus();
00310             return 1;               // Don't let the recipent know it was activated
00311         } 
00312     }
00313 
00314 // useful code to see where focus events originate from. Set a breakpoint below and look
00315 // at the call stack
00316     if ( event.GetEventType() == wxEVT_SET_FOCUS )
00317     {
00318         TRACEUSER("luke", _T("CCamApp::FilterEvent focus to %s"), pEventObject->GetClassInfo()->GetClassName());
00319 /*      if (pEventObject->IsKindOf(CLASSINFO(CRenderWnd)))
00320         {
00321             INT32 i=1;
00322         } */
00323     }
00324 
00325     if ( event.GetEventType() == wxEVT_KILL_FOCUS )
00326     {
00327 #if defined(_DEBUG)
00328         wxFocusEvent&   FocusEvent = (wxFocusEvent&)event;
00329         TRACEUSER( "luke", _T("CCamApp::FilterEvent kill focus to %016x from 0x%016x"), FocusEvent.GetWindow(), 
00330                 FocusEvent.GetEventObject() );
00331 #endif
00332 
00333         // Any loss of focus could well a good time to kill cursor
00334         wxSetCursor( *wxSTANDARD_CURSOR );
00335     }
00336 
00337     if (( event.GetEventType() == wxEVT_CREATE )
00338         && pEventObject
00339         && (pEventObject->IsKindOf(CLASSINFO(wxTopLevelWindow)))
00340         && !(pEventObject->IsKindOf(CLASSINFO(wxAdvSplashScreen))) // Don't trigger this on the creation of the splash screen itself
00341         && !(pEventObject->IsKindOf(CLASSINFO(wxSplashScreen)))
00342         )
00343     {
00344         // a top level window is about to be created. End the splash screen if it is up as it may obscure it
00345         CamResource::DoneInit(FALSE);   
00346     }
00347 
00348 #if defined(_DEBUG)
00349     if( event.GetEventType() == wxEVT_CHAR )
00350     {
00351         if (pEventObject)
00352         {
00353             TRACEUSER( "jlh92", _T("KeyEvent 4 %s CH\n"),
00354                 ((wxWindow*)pEventObject)->GetClassInfo()->GetClassName() );
00355         }
00356     }
00357 #endif
00358 
00359     if( event.GetEventType() == wxEVT_KEY_DOWN ||
00360         event.GetEventType() == wxEVT_KEY_UP )
00361     {
00362         // Use timestamp to detect events which are passing
00363         // down the chain (which we've tested)
00364         if( lLastTimeStamp == event.GetTimestamp() )
00365             return -1;
00366         lLastTimeStamp = event.GetTimestamp();
00367 
00368         TRACEUSER( "jlh92", _T("KeyEvent 4 %s %s\n"),
00369             ((wxWindow*)pEventObject)->GetClassInfo()->GetClassName(),
00370             event.GetEventType() == wxEVT_KEY_DOWN ? _T("KD") : _T("KU") );
00371         
00372         // Is the object allowed to recieve keys? We have to go done the object hierarchy
00373         // since some control (notably Combos) will produce temporary windows which can get
00374         // key events.
00375         wxWindow* pScanObj = (wxWindow*)pEventObject;
00376         while( NULL != pScanObj )
00377         {
00378             wxClassInfo* pClassInfo = pScanObj->GetClassInfo();
00379 #if defined(DEBUG_KEYPRESS_SPEW)
00380             {
00381                 wxClassInfo *pTmpInfo = pClassInfo;
00382                 while( NULL != pTmpInfo )
00383                 {
00384                     TRACEUSER( "jlh92", _T("Class %s\n"), PCTSTR(pTmpInfo->GetClassName()) );
00385         
00386                     PCTSTR  pszName = pTmpInfo->GetBaseClassName1();
00387                     pTmpInfo = NULL == pszName ? NULL : wxClassInfo::FindClass( pszName );
00388                 }
00389                 TRACEUSER( "jlh92", _T("----------------------\n") );
00390             }
00391 #endif
00392             TRACEUSER("amb", _T("CCamApp::FilterEvent key for %s"), pClassInfo->GetClassName());
00393 
00394             if( pClassInfo->IsKindOf( CLASSINFO(wxTextCtrl) ) ||
00395                 pClassInfo->IsKindOf( CLASSINFO(wxComboBox) ) ||
00396                 pClassInfo->IsKindOf( CLASSINFO(wxSliderCombo) ) ||
00397                 pClassInfo->IsKindOf( CLASSINFO(wxOwnerDrawnComboBox) ) ||
00398                 pClassInfo->IsKindOf( CLASSINFO(wxComboCtrl) )
00399                 )
00400             {
00401                 TRACEUSER("amb", _T("CCamApp::FilterEvent gets keys as special"));
00402                 TRACEUSER( "jlh92", _T("Control gets keys") );
00403                 // Yes, pass on as usual
00404                 return -1;
00405             }
00406 
00407             pScanObj = pScanObj->GetParent();
00408         }
00409 
00410         // Scan down ancestors looking for either wxPanels (always non-modal) and
00411         // wxDailogs (can be modal, so we check)
00412         wxWindow *pWnd = (wxWindow*)pEventObject;
00413         while( NULL != pWnd && !pWnd->IsKindOf( CLASSINFO(wxPanel) ) )
00414         {
00415             // Dialogs may-be modal so check
00416             if( pWnd->IsKindOf( CLASSINFO(wxDialog) ) )
00417             {
00418                 // Pass event down chain if modal
00419                 if( ((wxDialog*)pWnd)->IsModal() )
00420                 {
00421                     TRACEUSER( "jlh92", _T("Modal dialog\n") );
00422                     TRACEUSER("amb", _T("CCamApp::FilterEvent gets keys as modal"));
00423                     return -1;
00424                 }
00425 
00426                 // Non-modal dialog so do focus handling
00427                 break;
00428             }
00429 
00430             pWnd = pWnd->GetParent();
00431         }
00432 
00433         TRACEUSER("amb", _T("CCamApp::FilterEvent handle"));
00434         TRACEUSER( "jlh92", _T("Handled!\n") );
00435 
00436         // Do our best to see if the object is deleted.
00437         wxWindowDeletionWatcher * wd = NULL;
00438         if (pEventObject->IsKindOf(CLASSINFO(wxWindow)))
00439         {
00440             wd = new wxWindowDeletionWatcher((wxWindow*)pEventObject);
00441             if (!wd)
00442                 return -1;
00443         }
00444 
00445         // Process keyboard messages (and mark event as handled)
00446         if( HandleKeyPress( (wxKeyEvent&)event ) )
00447         {
00448             BOOL deleted = wd && wd->HasBeenDeleted();
00449             if (wd)
00450                 delete wd;
00451             if (deleted)
00452                 return 1; // event handled. Do NOT anything else here as the object may by now
00453                         // have been deleted (e.g. FileClose hotkey).
00454             else
00455                 return -1;
00456         }
00457         if (wd)
00458             delete wd;
00459     }
00460     
00461     return -1;
00462 }
00463 
00464 static bool GiveFocusToFocusableOffspring( wxWindow* pWnd )
00465 {
00466     TRACEUSER( "jlh92", _T("GF2FO class %s\n"), pWnd->GetClassInfo()->GetClassName() );
00467 
00468     // Can we give focus to passed window. Yes, give focus
00469     // and return happy
00470     if( pWnd->AcceptsFocus() )
00471     {
00472         TRACEUSER( "jlh92", _T("Focused!\n") );
00473         pWnd->SetFocus();
00474         return true;
00475     }
00476 
00477     // No, lets try the children then
00478     wxWindowList&       lstChild = pWnd->GetChildren();
00479     wxWindowListNode*   pNode = lstChild.GetFirst();
00480     while( NULL != pNode )
00481     {
00482         if( GiveFocusToFocusableOffspring( pNode->GetData() ) )
00483             return true;
00484 
00485         pNode = pNode->GetNext();
00486     }
00487     
00488     return false;
00489 }
00490 
00491 
00492 /***************************************************************************************************************************/
00493 //
00494 // Initialisation.
00495 //
00496 
00497 const wxString camIPC_START = _T("StartOther");
00498 
00499 class CamIPCConnection : public wxConnection
00500 {
00501 
00502 public:
00503     CamIPCConnection() : wxConnection(m_pBuffer, WXSIZEOF(m_pBuffer)) {}
00504 
00505     virtual bool OnExecute (const wxString& WXUNUSED(topic),
00506                             wxChar *data,
00507                             int /* TYPENOTE: Correct */ size,
00508                             wxIPCFormat WXUNUSED(format))
00509     {
00510         // argv buffer
00511         INT32 argc = 0;
00512 
00513         INT32 i;
00514         for (i=0; i<size; i++)
00515         {
00516             // exit if this is a NULL, and the last character was a NULL
00517             if (!data[i] && i && !data[i-1])
00518                 break;
00519 
00520             if (!data[i])
00521                 argc++;
00522         }
00523 
00524         wxChar ** argv = new wxChar*[argc];
00525 
00526         wxChar* p = data;
00527         for (i=0; i<argc; i++)
00528         {
00529             argv[i] = camStrdup(p);
00530             p+=wxStrlen(argv[i])+1; // move past null
00531         }
00532 
00533         BOOL result = wxGetApp().OnSecondInstance(argv, argc);
00534 
00535         // free memory
00536         for (i=0; i<argc; i++)
00537         {
00538             free(argv[i]);
00539         }
00540         delete [] argv;
00541 
00542         // return
00543         return result;
00544     }
00545 
00546 private:
00547     wxChar m_pBuffer[4096];
00548 
00549 };
00550 
00551 class CamIPCServer : public wxServer
00552 {
00553 public:
00554     virtual wxConnectionBase *OnAcceptConnection (const wxString& topic)
00555     {
00556         if (topic != camIPC_START)
00557             return NULL;
00558         else
00559             return new CamIPCConnection;
00560     }
00561 };
00562 
00563 // Global so we can use it for parsing second instance
00564 static const wxCmdLineEntryDesc cmdLineDesc[] =
00565 {
00566 #if defined(_DEBUG)
00567     { wxCMD_LINE_OPTION, _T("u"), _T("user"), _T("set username for debug tracing") },
00568     { wxCMD_LINE_SWITCH, _T("m"), _T("memorycheck"), _T("check memory") },
00569     { wxCMD_LINE_OPTION, _T("l"), _T("listdebug"), _T("list debug level") , wxCMD_LINE_VAL_NUMBER },
00570 #endif
00571     { wxCMD_LINE_SWITCH, _T("h"), _T("help"),   _T("Display this help"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
00572     { wxCMD_LINE_SWITCH, _T("v"), _T("version"),    _T("Display the version information") },
00573     { wxCMD_LINE_OPTION, _T("r"), _T("resource"),   _T("resource directory") },
00574     { wxCMD_LINE_SWITCH, _T("x"), _T("xrccheckgen"), _T("generate xrc.check file") },
00575     { wxCMD_LINE_PARAM, NULL, NULL, _T("input file"), wxCMD_LINE_VAL_STRING, 
00576                                         wxCMD_LINE_PARAM_OPTIONAL|wxCMD_LINE_PARAM_MULTIPLE },
00577     { wxCMD_LINE_NONE }
00578 };
00579 
00580 BOOL CCamApp::OnSecondInstance(wxChar** argv, INT32 argc)
00581 {
00582     // Parse command line. We do this early so we get flags which
00583     // are useful for init, such as -u
00584     //
00585     wxCmdLineParser parser(argc,argv);
00586     parser.SetDesc(cmdLineDesc);
00587     if (parser.Parse()) // Handles help automatically
00588     {
00589         return FALSE;
00590     }
00591     if (parser.GetParamCount()>=1)
00592     {
00593         for ( UINT32 i=0 ; i<parser.GetParamCount() ; i++ )
00594             m_docManager->CreateDocument(parser.GetParam(i),wxDOC_SILENT);
00595     }
00596     m_pMainFrame->Raise();
00597     return TRUE;
00598 }
00599 
00600 bool CCamApp::OnInit()
00601 {
00602     InInitOrDeInit = TRUE; // Don't allow the user to try carrying on working
00603     ::wxHandleFatalExceptions(TRUE);
00604 
00605     //
00606     // Parse command line. We do this early so we get flags which
00607     // are useful for init, such as -u
00608     //
00609     wxCmdLineParser parser(argc,argv);
00610     parser.SetDesc(cmdLineDesc);
00611     if (parser.Parse()) // Handles help automatically
00612     {
00613         return FALSE;
00614     }
00615 
00616     wxString ResourceDir = _T("");
00617     if (parser.Found(_T("r"), &ResourceDir))
00618     {
00619         if (!ResourceDir.IsEmpty())
00620         {
00621             CamResource::SetResourceFilePath(ResourceDir);
00622         }
00623 
00624         if ( parser.Found( _T("x") ) )
00625         {
00626             CamResource::SetGenerateXRCCheck(TRUE);
00627         }
00628     }
00629 
00630     if( parser.Found( _T("v") ) )
00631     {
00632         wxString            strMessage;
00633 
00634 #if defined(__WXMSW__)
00635         strMessage = wxString::Format( wxT("Xara Xtreme\nVersion: %s\nCDraw Version: %d.%03d\n"), 
00636             g_pszAppVersion, HIWORD(GDraw_GetVersion()), LOWORD(GDraw_GetVersion()) );
00637 #else
00638 #if FALSE == wxUSE_UNICODE
00639         TCHAR*          pszCDrawVer = GDraw_GetSvnVersion();
00640 #else
00641         TCHAR           pszCDrawVer[32];
00642         camMbstowcs( pszCDrawVer, GDraw_GetSvnVersion(), 31 );
00643 #endif
00644         strMessage = wxString::Format( wxT("Xara Xtreme\nVersion: %s (%s)\nCDraw Version: %d.%03d (%s)\nBuild date: %s\n"), 
00645             g_pszAppVersion, g_pszSvnVersion, HIWORD(GDraw_GetVersion()), LOWORD(GDraw_GetVersion()), pszCDrawVer, CAMELOT_BUILD_DATE );
00646 #endif
00647 
00648         camPrintf( strMessage.c_str() );
00649         
00650         return FALSE;
00651     }
00652     
00653 #if defined(_DEBUG)
00654     if (parser.Found(_T("m"))) SimpleCCObject::CheckMemoryFlag=1;
00655 
00656     long listlevel; // TYPENOTE: Correct - wxWidgets doesn't know about INT32 etc.
00657     if (parser.Found(_T("l"), &listlevel))
00658     {
00659         List::ListDebugLevel = listlevel;
00660     }
00661 
00662     // Set up the username for tracing
00663     // We should default this to the environment setting for (say) LOGNAME
00664     wxString Username = _T("");
00665 
00666     // Overwrite with LOGNAME if it is set
00667     wxGetEnv(_T("LOGNAME"), &Username);
00668 
00669     // Overwrite with -u option if it is set
00670     parser.Found(_T("u"), &Username);
00671 
00672     Error::SetUserName(Username);
00673 
00674     if (Username==_T(""))
00675     {
00676         TRACEUSER("ALL", _T("No user specific trace output\n"));
00677     }
00678     else
00679     {
00680 //      TRACEUSER("ALL",_T("Tracing output where user is %s\n"),(const char *)Username.mb_str(wxConvUTF8));
00681         TRACEUSER("ALL",_T("Tracing output where user is %s\n"),(const TCHAR *)Username.c_str());
00682     }
00683 
00684     TRACEUSER("ALL",_T("Memory debugging %d, List debugging %d\n"), SimpleCCObject::CheckMemoryFlag, List::ListDebugLevel);
00685 
00686 #endif
00687 
00688     // OK, now we've handled the help case, and some VERY early init, we should see if another instance
00689     // is running.
00690 
00691     // Set and check for single instance running
00692     wxString SIname = wxString(_T(".XARA-XTREME-WX-"))  +GetAppName()+wxString::Format(_T("-%s"), wxGetUserId().c_str());
00693     wxFileName IPCfn(wxGetHomeDir(),SIname+_T(".ipc"));
00694     wxString IPCname = IPCfn.GetFullPath();
00695 
00696     m_pSingleInstanceChecker = NULL;
00697     m_pServer = NULL;
00698 
00699 #ifdef _DEBUG
00700     BOOL SingleInstanceCheck = FALSE;
00701 #else
00702     BOOL SingleInstanceCheck = TRUE;
00703 #endif
00704 
00705     if (SingleInstanceCheck)
00706     {
00707         // Create a single instance checker at that location
00708         m_pSingleInstanceChecker = new wxSingleInstanceChecker(SIname);
00709         if (!m_pSingleInstanceChecker)
00710         {
00711             ERROR2(FALSE, "Failed to create single instance checker");
00712         }
00713     
00714         // Now see if another is running
00715         if (m_pSingleInstanceChecker->IsAnotherRunning())
00716         {
00717             wxClient Client;
00718             wxConnectionBase * Connection = Client.MakeConnection(wxEmptyString, IPCname, camIPC_START);
00719     
00720             // If there is no connection, perhaps the other end is dead. We will start up anyway.
00721             if (Connection)
00722             {
00723                 INT32 len=1; // terminating null
00724                 INT32 i;
00725     
00726                 wxArrayString docs;
00727                 INT32 doccount = parser.GetParamCount()+1; // add one for the dummy
00728     
00729                 // Add all docs with a dummy argv[0]
00730                 for ( i=0 ; i<doccount; i++ )
00731                 {
00732                     wxString docname;
00733                     if (i)
00734                     {
00735                         docname = parser.GetParam(i-1);
00736                         wxFileName fn(docname);
00737                         fn.Normalize(wxPATH_NORM_ALL);
00738                         docname=fn.GetFullPath();
00739                     }
00740                     else
00741                     {
00742                         docname=argv[0];
00743                     }
00744                     len+=docname.length()+1; // include the trailing zero
00745                     docs.Add(docname);
00746                 }
00747     
00748                 wxChar * Data = new wxChar[len];
00749                 if (!Data)
00750                 {
00751                     ERROR2(FALSE, "Failed to create single instance checker data");
00752                 }
00753     
00754                 // Copy the 
00755                 wxChar * p = Data;
00756                 for (i = 0; i < doccount; i++)
00757                 {
00758                     wxStrcpy(p, docs[i]);
00759                     p+=docs[i].length()+1; // move past string and terminating NULL
00760                 }
00761                 *p = _T('\0'); // add a final terminating NULL
00762     
00763                 // Now send the data over the connection
00764                 if (Connection->Execute (Data, len*sizeof(wxChar)))
00765                 {
00766                     delete [] Data;
00767                     delete Connection;
00768     
00769                     //.Free up the single instance checker
00770                     delete m_pSingleInstanceChecker;
00771                     m_pSingleInstanceChecker = NULL;
00772     
00773                     // We're out of here...
00774                     return FALSE;
00775                 }
00776     
00777                 // Hmmmm, it didn't want to execute it. perhaps the other process is stuck. We'll run anyway
00778                 delete [] Data;
00779                 delete Connection;
00780             }
00781         }
00782     }
00783 
00784     // OK, we are the only instance running. Delete any stale socket (ours has not been created yet).
00785     ::wxRemoveFile(IPCname);
00786 
00787     // Register the image handler which loads CURs (used for Cursors, obviously)
00788     wxImage::AddHandler( new wxCURHandler );
00789 
00790     // Register the image handler which loads PNGs (used for TBs)
00791     wxImage::AddHandler( new wxPNGHandler );
00792 
00793     // Init the BinReloc stuff (we don't really care if this fails, since it
00794     // fails safe)
00795     BrInitError error;
00796     br_init( &error );
00797     
00798     // Useful debug tracing enablers, left here for next debug session...
00799 //  wxLog::AddTraceMask( _T("focus") );
00800 //  wxLog::AddTraceMask( _T("keyevent") );
00801 
00802     // Initialise the MonotonicTime class
00803     MonotonicTime::Init();
00804 
00805     // We initialize profiling here to allow the rest of the app to be profiled
00806     CamProfile::Init();
00807     // Don't start profiling until Alex has finished the code!
00808     CamProfile::ActivateProfiling(TRUE);
00809     // Indicate time from now on should be assigned to "OTHER"
00810     CamProfile::AtBase(CAMPROFILE_OTHER);
00811 
00812     TRACET(_T("CCamApp::OnInit first available time to trace"));
00813 
00814     // Initialize resources system
00815     if (!CamResource::Init()) return FALSE;
00816     // Initialize the art provider - needed for dialogs
00817     wxPlatformDependent::Init(CLASSINFO(CamPlatformDependent));
00818     if (!CamArtProvider::Init()) return FALSE;
00819     // We need this pretty early so we can handle ERROR boxes etc
00820     if (!DialogEventHandler::Init()) return FALSE;
00821     if (!ControlList::Init()) return FALSE;
00822 
00823     TRACET(_T("CCamApp::Calling Camelot.Init"));
00824 
00825     // Initialise the kernel application object & Prefs
00826     if( !Camelot.Init() )
00827         return false;
00828 
00829     // --------------------------------------------------------------------------
00830     // Detect first-time run and make Open File dialog default to Examples folder
00831     if (Camelot.DeclareSection(TEXT("Preferences"), 10))
00832     {
00833         Camelot.DeclarePref(NULL, TEXT("FirstRun"), &bFirstRun, 0, 1);
00834     }
00835 
00836     // Check the resource dir exists
00837     Camelot.DeclarePref( NULL, TEXT("ResourceDirOverride"), &m_strResourceDirPathOverride );
00838     m_strResourceDirPath = m_strResourceDirPathOverride; // this way, the path we find never gets put within the preferences
00839     if( /*bFirstRun ||*/ m_strResourceDirPath == _T("") || !wxDir::Exists( (PCTSTR)m_strResourceDirPath ) ) // AB: don't need to do this on first run especially
00840     {
00841 #if !defined(RESOURCE_DIR)
00842         // we can't use auto pointers here because they free using delete but BR allocates using malloc (strdup actually)
00843         char * pszDataPath = br_find_data_dir( "/usr/share" );
00844         if (pszDataPath)
00845         {
00846             m_strResourceDirPath = wxString( pszDataPath, wxConvFile );
00847             free(pszDataPath);
00848             m_strResourceDirPath += _T("/xaralx");
00849             TRACEUSER( "luke", _T("Using resource directory \"%s\"\n"), PCTSTR(m_strResourceDirPath) );
00850 #if defined(_DEBUG)
00851             if( !wxDir::Exists( PCTSTR(m_strResourceDirPath) ) )
00852             {
00853                 // We'll try default location under debug to make life easier
00854                 m_strResourceDirPath = _T("/usr/share/xaralx");
00855                 TRACEUSER( "luke", _T("Try = \"%s\"\n"), PCTSTR(m_strResourceDirPath) );
00856             }
00857 #endif
00858         }
00859 #else
00860         // The "" is needed to stop the macro expanding to LRESOURCE_DIR
00861         m_strResourceDirPath = _T(""RESOURCE_DIR);
00862 #endif
00863     }
00864     TRACEUSER( "luke", _T("ResDir = %s\n"), PCTSTR(m_strResourceDirPath) );
00865 
00866     // Get the media replay application setting
00867     Camelot.DeclarePref( NULL, TEXT("MediaApplication"), &m_strMediaApplication );
00868 
00869     TRACET(_T("CCamApp::Calling InitKernel"));
00870     // then initialise the kernel (and almost everything else)  
00871     if( !InitKernel() )
00872         return false;
00873 
00874     if( !Camelot.LateInit() )
00875         return false;
00876 
00877     TRACET(_T("CCamApp::Calling GRenderRegion::Init"));
00878     if (!GRenderRegion::Init(true))
00879         return false;
00880 
00881     // Declare the prefs for the window size and state
00882     if (Camelot.DeclareSection(TEXT("Windows"), 10))
00883     {
00884         Camelot.DeclarePref(NULL, TEXT("MainWndMax"), &MainWndMaximized, 0, 1);
00885         Camelot.DeclarePref(NULL, TEXT("MainWndMin"), &MainWndMinimized, 0, 1);
00886         Camelot.DeclarePref(NULL, TEXT("MainWndPos"), &MainWndPosString);
00887     }
00888 
00889     TRACET(_T("CCamApp::Making Doc Manager"));
00890     
00891     // Create the document manager and register our doc template
00892     m_docManager = std::auto_ptr<wxDocManager>( new wxDocManager() );
00893 
00894     wxDocTemplate      *pDocTemplate;
00895     pDocTemplate = new CCamDocTemplate(
00896         m_docManager.get(), wxT("Xara"), wxT("*.xar;*.web"), wxT(""), wxT("xar"), wxT("Xara document"), 
00897         wxT("Text View"),
00898         CLASSINFO(CCamDoc),
00899         CLASSINFO(CCamView) );
00900 //  pDocTemplate = new CCamDocTemplate(
00901 //      m_docManager.get(), wxT("Xara"), wxT("*.web"), wxT(""), wxT("web"), wxT("Xara document"), 
00902 //      wxT("Text View"),
00903 //      CLASSINFO(CCamDoc),
00904 //      CLASSINFO(ScreenCamView) );
00905 
00906     // Reload the file history (9 entries)
00907     wxFileHistory*      pFileHist = m_docManager->GetFileHistory();
00908     for( UINT32 ord = 0; ord < 9; ++ord )
00909     {
00910         // This is safe since we control all variables!
00911         TCHAR           pszTag[8];
00912         camSprintf( pszTag, _T("File%d"), ord );
00913 
00914         String_256      strFileName;
00915         Camelot.GetPrefDirect( _T("Recent File list"), pszTag, &strFileName );
00916         
00917         if( strFileName != _T("") )
00918             pFileHist->AddFileToHistory( PCTSTR(strFileName) );
00919     }
00920 
00921     if (bFirstRun)
00922     {
00923         // Set File Open dialog location to our Examples folder
00924         wxString    strConfigPath( (TCHAR*)m_strResourceDirPath );
00925         strConfigPath += _T("/Examples");
00926 
00927 #if defined(_DEBUG)
00928         // Debug-only fallback
00929         if (!wxDir::Exists(strConfigPath))
00930             strConfigPath = _T("/usr/share/xaralx/Examples");
00931 #endif
00932 
00933         if (wxDir::Exists(strConfigPath))
00934             BaseFileDialog::DefaultOpenFilePath = strConfigPath;
00935     }
00936 
00937     // NOTE! Set bFirstRun = FALSE in OnExit handler below
00938     // --------------------------------------------------------------------------
00939 
00940     // Set idles to only get sent to windows that want them
00941     wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); 
00942 
00943     // Create the Frame window
00944     //
00945     // get user preference info for main window
00946     wxSize ScreenSize = ::wxGetDisplaySize();
00947     wxRect WndRect;
00948     wxSize OldScreenSize;
00949     if ((camSscanf(MainWndPosString, _T("%d %d %d %d %d %d"),
00950             &WndRect.x, &WndRect.y, &WndRect.width, &WndRect.height, &OldScreenSize.x, &OldScreenSize.y) == 6) &&
00951             (WndRect.width > 0) && (WndRect.height > 0))
00952     {
00953         // numbers scanned OK, scale them to fit current screen size
00954         if (OldScreenSize.x != ScreenSize.x)
00955         {
00956             // if screen size different from last time, them scale them
00957             WndRect.x = MulDiv(WndRect.x, ScreenSize.x, OldScreenSize.x);
00958             WndRect.width = MulDiv(WndRect.width, ScreenSize.x, OldScreenSize.x);
00959         }
00960         if (OldScreenSize.y != ScreenSize.y)
00961         {
00962             WndRect.y = MulDiv(WndRect.y, ScreenSize.y, OldScreenSize.y);
00963             WndRect.height = MulDiv(WndRect.height, ScreenSize.y, OldScreenSize.y);
00964         }
00965     }
00966     else
00967     {
00968         // make up a sensible default position for the window, inset five percent
00969         // in x and 10 percent in y to avoid taskbars on linux
00970         WndRect.x = ScreenSize.x / 20;
00971         WndRect.width = ScreenSize.x - WndRect.x * 2;
00972         WndRect.y = ScreenSize.y / 10;
00973         WndRect.height = ScreenSize.y - WndRect.y * 2;
00974     }
00975 
00976     TRACET(_T("CCamApp::Making Frame Window"));
00977     m_pMainFrame = new CCamFrame( m_docManager.get(), (wxFrame *)NULL, wxT("Xara Xtreme"), 
00978         WndRect.GetPosition(), WndRect.GetSize(), wxDEFAULT_FRAME_STYLE);
00979 
00980     m_pMainFrame->Show(FALSE); // Don't show it yet
00981 
00982 #if !defined(XARA_MENUGEN)
00983     TRACET(_T("CCamApp::Making Menu structure"));
00984     //
00985     // Build the MDI style file menu
00986     // This is just a simple menu. The full menu is created
00987     // after loading a document.
00988     //
00989     wxMenu* pFileMenu = new wxMenu;
00990 
00991     pFileMenu->Append( wxID_NEW,  wxT("&New...") );
00992     pFileMenu->Append( wxID_OPEN, wxT("&Open...") );
00993 
00994 #if defined(FILELIST)
00995     wxMenu* pRecentFilesMenu = new wxMenu;
00996     m_docManager->FileHistoryUseMenu(pRecentFilesMenu);
00997     m_docManager->FileHistoryAddFilesToMenu(pRecentFilesMenu);
00998 
00999     pFileMenu->AppendSeparator();
01000     pFileMenu->Append( -1, wxT("&Recent files"),pRecentFilesMenu );
01001 #endif //defiend(FILELIST)
01002 
01003     pFileMenu->AppendSeparator();
01004     pFileMenu->Append( wxID_EXIT, wxT("E&xit") );
01005 
01006     // Build help menu
01007     wxMenu             *pHelpMenu = new wxMenu;
01008     pHelpMenu->Append( _R(DOCVIEW_ABOUT), wxT("&About...") );
01009 
01010     // Place menus into the menu bar
01011     wxMenuBar          *pMenuBar = new wxMenuBar;
01012     pMenuBar->Append( pFileMenu, wxT("File") );
01013     pMenuBar->Append( pHelpMenu, wxT("Help") );
01014 
01015 #ifdef __WXMAC__
01016     wxMenuBar::MacSetCommonMenuBar( pMenuBar );
01017 #endif //def __WXMAC__
01018 
01019     // Set up menu bar...
01020     m_pMainFrame->SetMenuBar( pMenuBar );
01021 
01022 #else
01023 
01024 #ifdef __WXMAC__
01025     wxMenuBar::MacSetCommonMenuBar( WinMDIMenu );
01026 #endif //def __WXMAC__
01027 
01028     // Set up menu bar...
01029     m_pMainFrame->SetMenuBar( WinMDIMenu );
01030     WinMDIMenu->ClearAccelTable();
01031 
01032 #endif
01033 
01034     // We don't want auto-accelerators, this is done using our hotkeys
01035     // I don't know how to do this yet, but I'm looking....
01036 //  wxAcceleratorTable* pAccelTable = pMenuBar->GetAccelTable();
01037 //  *pAccelTable = wxAcceleratorTable();
01038 
01039     TRACET(_T("CCamApp::Init Setting mainframe as top window"));
01040 
01041     m_pMainFrame->CreateToolbars();
01042     m_pMainFrame->UpdateFrameManager();
01043 
01044     // Show the main frame window
01045     // make maximized if thats what we were last time, unless overridden by user
01046     if (MainWndMaximized)
01047     {
01048         m_pMainFrame->Maximize();
01049     }
01050     if (MainWndMinimized)
01051     {
01052         m_pMainFrame->Iconize();
01053     }
01054     SetTopWindow( m_pMainFrame );
01055     ::wxYield(); // allow resizing to take place
01056     m_pMainFrame->Show( true );
01057     ::wxYield(); // allow resizing to take place
01058     wxPlatformDependent::Get()->FixUpdate(m_pMainFrame); // Force the main frame to be redrawn properly
01059     ::wxYield(); // allow resizing to take place
01060 
01061 #ifndef EXCLUDE_FROM_XARALX
01062     m_pMainFrame->CacheNormalPlaceMode();
01063     m_pMainFrame->CheckFullScreenMode();
01064 
01065     // if the splash box is up, draw our window behind it (will be a big pending WM_PAINT)
01066     // IT MUST NOT BE ACTIVE else palette problems
01067     if (AfxOleGetUserCtrl())
01068     {
01069         if (m_nCmdShow == SW_SHOWMINIMIZED || m_nCmdShow == SW_SHOWMINNOACTIVE)
01070         {
01071             pMainFrame->ShowWindow(SW_SHOWMINNOACTIVE);
01072         }
01073         else
01074         {
01075             if (m_nCmdShow == SW_SHOWMAXIMIZED)
01076                 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
01077             else
01078                 pMainFrame->ShowWindow(SW_SHOWNOACTIVATE);
01079 
01080             // the ShowWindow() above has made the main window active so make the splash box active, else
01081             // we get nasty palette problems later on
01082             pSplashbox->SetActiveWindow();
01083         }
01084     }
01085 #endif
01086 
01087     Tool::SelectFirstTool();
01088 
01089     // Go through the command line and load documents
01090     TRACET(_T("CCamApp::Init Loading docs (if any) from command line"));
01091 
01092     if( 0 == parser.GetParamCount() )
01093         m_docManager->CreateDocument( _T(""), wxDOC_NEW );
01094     else
01095     {
01096         for ( UINT32 i=0 ; i<parser.GetParamCount() ; i++ )
01097             m_docManager->CreateDocument(parser.GetParam(i),wxDOC_SILENT);
01098     }
01099 
01100     // Remove the splash screen
01101     CamResource::DoneInit();
01102 
01103     CXMLUtils::Initialise();
01104 
01105     if (SingleInstanceCheck)
01106     {
01107         // We are able to load documents, so now start our own IPC server
01108         m_pServer = new CamIPCServer();
01109         if (!m_pServer)
01110         {
01111             delete (m_pSingleInstanceChecker);
01112             m_pSingleInstanceChecker = NULL;
01113             ERROR2(FALSE, "Failed to create IPC server");
01114         }
01115     
01116         // and initialize it
01117         if (!(m_pServer->Create(IPCname)))
01118         {
01119             delete m_pServer;
01120             m_pServer = NULL;
01121     
01122             delete (m_pSingleInstanceChecker);
01123             m_pSingleInstanceChecker = NULL;
01124             ERROR2(FALSE, "Failed to init IPC server");
01125         }
01126     }
01127 
01128     // Give focus to any child that will take it, parent can't have it since
01129     // it's a frame (see gtk_widget_grab_focus)
01130     GiveFocusToFocusableOffspring( m_pMainFrame );
01131     
01132     // Create timer used for background rendering.
01133 //  m_Timer.SetOwner(this,CAM_TIMER_ID);
01134 //  m_Timer.Start(CAM_TIMER_FREQUENCY);
01135 
01136     InInitOrDeInit = FALSE; // Now allow the user a chance to save their work on a SEGV
01137 
01138     return true;
01139 }
01140 
01141 /***************************************************************************************************************************/
01142 //
01143 // Deinitialisation.
01144 //
01145 
01146 INT32 CCamApp::OnExit( void )
01147 {
01148     InInitOrDeInit = TRUE; // Don't allow them to save their work on a SEGV
01149     // We can no longer stop the closedown, so flag this fact
01150     Camelot.ShuttingDown(TRUE);
01151 
01152     // Dump the file history (9 entries as for Xtreme 4 Win)
01153     wxFileHistory*      pFileHist = m_docManager->GetFileHistory();
01154     UINT32              cRecent   = UINT32(pFileHist->GetCount());
01155     for( UINT32 ord = 0; ord < 9; ++ord )
01156     {
01157         // This is safe since we control all variables!
01158         TCHAR           pszTag[8];
01159         camSprintf( pszTag, _T("File%d"), ord );
01160 
01161         if( ord < cRecent )
01162         {
01163             wxString    strFileName( pFileHist->GetHistoryFile( ord ) );
01164             Camelot.SetPrefDirect( _T("Recent File list"), pszTag, PCTSTR(strFileName), TRUE );
01165         }
01166         else
01167             Camelot.SetPrefDirect( _T("Recent File list"), pszTag, _T(""), TRUE );
01168     }
01169 
01170     // we can't load documents any more - delete IPC server
01171     if (m_pServer)
01172     {
01173         delete m_pServer;
01174         m_pServer = NULL;
01175     }
01176 
01177     // delete single instance checked
01178     if (m_pSingleInstanceChecker)
01179     {
01180         delete m_pSingleInstanceChecker;
01181         m_pSingleInstanceChecker = NULL;
01182     }
01183 
01184     // Rendering is back on idle events for now as it actually works
01185 //  m_Timer.Stop();
01186 
01187 #if defined(FILELIST)
01188     {
01189         m_docManager->FileHistorySave(Preferences::GetOilPrefs());
01190     }
01191 #endif
01192     m_docManager = std::auto_ptr<wxDocManager>( NULL );
01193 
01194     bFirstRun = FALSE;
01195 
01196     // Now deinit everything
01197 
01198     CXMLUtils::DeInitialise();
01199 
01200     DeinitKernel();
01201 
01202 #if CUSTOM_INONE == 2
01203     DLLControlClass::DeinitAllControls();
01204 #endif
01205 
01206     GRenderRegion::DeInit();                        // tidy up GDraw
01207 
01208 PORTNOTE("other","Removed GDI+, filelist and profilename support")
01209 #ifndef EXCLUDE_FROM_XARALX
01210     Gdiplus::GdiplusShutdown(gdiplusToken);
01211 
01212     // Finished with preferences/registry so remove the allocated ProfileName. Was not here before 18/2/97
01213     if (m_pszProfileName != NULL)
01214     {
01215         free((void *) m_pszProfileName);
01216         m_pszProfileName = NULL;
01217     }
01218 #endif
01219 
01220     ControlList::DeInit();
01221     DialogEventHandler::DeInit();
01222     // Kill of art provider
01223     CamArtProvider::DeInit();
01224     wxPlatformDependent::DeInit();
01225     // Kill of resources
01226     CamResource::DeInit();
01227 
01228     // Kill off profiling
01229     CamProfile::ActivateProfiling(FALSE);
01230 
01231 #if DUMP_MEM_AT_END
01232     MemoryState.DumpAllObjectsSince();
01233 #endif
01234 
01235     // We want a memory dump on Debug builds only
01236 #ifdef _DEBUG
01237     SimpleCCObject::MemoryDump();
01238     DumpCCMallocTrace();
01239 #endif
01240     
01241 PORTNOTE("other","Removed 3D, Extras and UserHelp support")
01242 #ifndef EXCLUDE_FROM_XARALX
01243     // For fabby 3D
01244     if (Is3dWanted())
01245         pCtl3dUnregister(AfxGetInstanceHandle()); 
01246 
01247     OILModule::DeinitExtras();                          // free all DLLs (e.g. ctl3d)
01248 
01249     // Last of all, deinit the help system now that there's very little else to go wrong.
01250     DeInitUserHelp();
01251 #endif
01252 
01253     // zap this after we know all windows have gone
01254     wxWindowDeletionWatcher::DeInit();
01255 
01256     ::wxHandleFatalExceptions(FALSE);
01257     return wxApp::OnExit();
01258 }
01259 
01260 //  WEBSTER-ranbirr-12/11/96
01261 #ifndef WEBSTER
01262 void CCamApp::OnFilePrintSetup()
01263 {
01264 #ifndef STANDALONE
01265     Document *pDoc = Document::GetSelected();
01266     DocView *pDocView = DocView::GetSelected();
01267 
01268     if (pDoc && pDocView && pDocView->GetConnectionToOilView())
01269     {
01270         // Inform the user if we have switched to using the default printer on the system
01271         // before opening the print setup dlg.
01272         CCPrintDialog::InformResetToDefaultPrinter(FALSE);
01273     
01274         // This no longer calls the base class OnFilePrint() function.
01275         // Instead, we involke the print dlg ourselves so that we can update our
01276         // printer settings when the dlg is closed via the user clicking on OK
01277         // (7/4/95 - Markn)
01278 
01279         CCPrintInfo printinfo(pDoc, pDocView->GetConnectionToOilView());
01280         printinfo.OnPreparePrinting(TRUE);          
01281     }
01282     
01283 #endif
01284 }
01285 #endif
01286 
01287 void CCamApp::OnAppExit()
01288 {
01289 PORTNOTE("other","Removed multi-instance flag stuff")
01290 #ifndef EXCLUDE_FROM_XARALX
01291     // remove the flag that prevents camelot starting more than once; BUT only if were
01292     // the camelot that set it!
01293 
01294     HWND mainWindow = m_pMainWnd->m_hWnd;
01295     
01296     if (mainWindow)
01297     {
01298         BOOL* ret = (BOOL*) RemoveProp (m_pMainWnd->m_hWnd, "Xara X sfs");
01299 
01300         if (ret) delete (ret);
01301     }
01302 #endif  
01303 
01304     // Now close the main frame
01305     m_pMainFrame->Close();
01306 
01307 }
01308 
01309 
01310 /********************************************************************************************
01311 
01312 >   void CCamApp::HandleKeyPress( wxKeyEvent& event )
01313 
01314     Author:     Luke_Hart (Xara Group Ltd) <lukeh@xara.com>
01315     Created:    22/05/06
01316     Inputs:     event - The key \ char event to handle
01317     Returns:    true if handled else false
01318     Purpose:    Central handler for key and char events, using KeyPress class to route
01319                 events to the areas of code that need to handle them
01320 
01321 ********************************************************************************************/
01322 
01323 bool CCamApp::HandleKeyPress( wxKeyEvent& event )
01324 {
01325     // Make sure the kernel knows which view/doc the event applies to, if any.
01326     if( NULL != Document::GetSelected() )
01327         Document::GetSelected()->SetCurrent();
01328     if( NULL != DocView::GetSelected() )
01329         DocView::GetSelected()->SetCurrent();
01330 
01331     // Process keyboard messages (returning true if it was)
01332     return !CCamFrame::GetMainFrame()->IsIconized() && KeyPress::TranslateMessage( (wxKeyEvent*)&event );
01333 }
01334 
01335 
01336 /********************************************************************************************
01337 
01338 >   void CCamApp::OnFileOpen()
01339 
01340     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01341     Created:    14/2/95
01342     Purpose:    Displays the File Open dialog and opens whichever file was selected.
01343 
01344 ********************************************************************************************/
01345 
01346 void CCamApp::OnFileOpen()
01347 {
01348 #ifndef EXCLUDE_FROM_RALPH
01349     // Build the list of filters
01350     INT32 NativeFilterPos = 0;
01351     TCHAR* pFilters = OpenFileDialog::BuildFilterString(&NativeFilterPos);
01352 
01353     TRACEUSER( "luke", _T("Filters = %s"), pFilters );
01354 
01355     // Set up the dialog
01356     OpenFileDialog OpenDialog(pFilters);
01357     OpenDialog.NativeFilterPos = NativeFilterPos;
01358     OpenDialog.PrepareDialog();     
01359     
01360     // Display the dialog and get the filename we require
01361     BOOL Result = OpenDialog.OpenAndGetFileName();
01362 
01363     // Free up the memory allocated by BuildFilterString
01364     CCFree(pFilters);
01365 
01366     // If they did not click on OK then stop right now
01367     if (!Result)
01368         return;
01369 
01370     // Remember the filter for later in the opening sequence
01371     OpenDialog.SelectedFilter = OpenDialog.GetSelectedFilterIndex();
01372 
01373     // Get the filename, ensuring that the path is valid
01374     PathName Path;
01375     OpenDialog.GetChosenFileName(&Path);
01376     String_256 Str = Path.GetPath();
01377 
01378     // Extract directory name (minus terminating backslash) and remember for next time.
01379     OpenDialog.SetDefaultPath(Path.GetLocation(FALSE));
01380 
01381     // Andy Hills, 05-02-2001
01382     // Fix for bug 6712:
01383 
01384     // Delete the preview bitmap, if present.
01385     // If we don't delete it here, when we call OpenDocumentFile (below)
01386     // all global bitmaps are deleted (as part of the process of closing all
01387     // existing documents), including the preview bitmap.
01388     // Unfortunately, the OILBitmap is deleted without deleting the
01389     // KernelBitmap which owns it; thus, at the end of this function, when the
01390     // file dialogue is destructed, Camelot tries to destruct the preview
01391     // bitmap even though its ActualBitmap has already been deleted, causing
01392     // an access violation.
01393     // It is safer to destroy both the kernel bitmap and (implicitly) its
01394     // OILBitmap here.
01395 
01396 PORTNOTE( "other" ,"Removed open preview clean-up" )
01397 #ifndef EXCLUDE_FROM_XARALX
01398     // There is a more general problem, in that when we close all documents
01399     // we get rid of all global bitmaps. I don't believe it is safe to assume
01400     // that all global bitmaps belong to the documents which are being closed.
01401     // I.e. I think we should only delete bitmaps which we are sure belong to
01402     // the documents.
01403     if (OpenDialog.pBitmapToUse != NULL)
01404     {
01405         delete OpenDialog.pBitmapToUse;
01406         OpenDialog.pBitmapToUse = NULL;
01407     }
01408 #endif
01409 
01410     // and open the file. if returns NULL, the user has already been alerted
01411     wxDocument* pDoc = OpenDocumentFile( Str );
01412     if (pDoc!=NULL)
01413     {
01414         // Make sure that the files name is sensible
01415         MakeDocumentNative(pDoc, &Path);
01416         
01417         // add it to the recent file list
01418         AddToRecentFileList( PCTSTR(Str) );
01419 
01420         // ... and set the path as the "original" path to the doc.  This will be used to 
01421         // "restore" the doc when we next run, if it was open when we shut down.
01422         ((CCamDoc*) pDoc)->SetOriginalPath(Str);
01423     }
01424 #endif
01425 }
01426 
01427 
01428 /********************************************************************************************
01429 
01430 >   virtual void CCamApp::AddToRecentFileList(LPCTSTR pPathName)
01431 
01432     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01433     Created:    8/5/95
01434     Inputs:     pPathName - the full path name of the file to add to the list
01435     Purpose:    Adds the file to the recent file list
01436 
01437 ********************************************************************************************/
01438 
01439 void CCamApp::AddToRecentFileList(LPCTSTR pPathName)
01440 {
01441     // Make sure we have not been passed a load of junk
01442     ERROR3IF(pPathName==NULL, "NULL path name in AddToRecentFilelist\n");
01443 
01444     wxFileHistory*      pFileHist = m_docManager->GetFileHistory();
01445     pFileHist->AddFileToHistory( pPathName );
01446 }
01447 
01448 
01449 /********************************************************************************************
01450 >   virtual CDocument* CCamApp::OpenDocumentFile(LPCTSTR lpcszFileName)
01451 
01452     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01453     Created:    4/7/95
01454     Inputs:     lpcszFileName               path to the document file to load
01455     Returns:    A pointer to the MFC CDocument object that manages the opened file, or
01456                 NULL if it can't be loaded for some reason.
01457     Purpose:    We override this implementation function so that when the user tries to
01458                 load a document that is already loaded, we can display a dialog box with
01459                 various load options, instead of simply bringing the document's view
01460                 to the front.
01461 
01462                 This function is largely copied from the MFC equivalent in APPUI.CPP.
01463     Errors:     -
01464     SeeAlso:    -
01465 ********************************************************************************************/
01466 
01467 wxDocument* CCamApp::OpenDocumentFile( PCTSTR lpcszFileName )
01468 {
01469     // find the highest confidence
01470 
01471     wxList&             listTemplates( GetDocumentManager()->GetTemplates() );
01472     wxNode*             pNode = listTemplates.GetFirst();
01473 
01474     CCamDocTemplate::Confidence bestMatch = CCamDocTemplate::noAttempt;
01475     CCamDocTemplate*    pBestTemplate = NULL;
01476     wxDocument*         pOpenDocument = NULL;
01477     wxDocument*         pNewDoc       = NULL;
01478 
01479     TCHAR               szPath[_MAX_PATH + 1];
01480     {
01481         wxFileName      FileName( lpcszFileName );
01482         camStrncpy( szPath, FileName.GetFullPath(), _MAX_PATH );
01483     }
01484 
01485     while (pNode != NULL)
01486     {
01487         CCamDocTemplate* pTemplate = (CCamDocTemplate*)pNode->GetData();
01488         ASSERT( pTemplate->IsKindOf( CLASSINFO(CCamDocTemplate) ) );
01489 
01490         CCamDocTemplate::Confidence match;
01491         ASSERT(pOpenDocument == NULL);
01492         match = pTemplate->MatchDocType(szPath, pOpenDocument);
01493 
01494         if (match > bestMatch)
01495         {
01496             bestMatch = match;
01497             pBestTemplate = pTemplate;
01498         }
01499 
01500         if (match == CCamDocTemplate::yesAlreadyOpen) break;
01501 
01502         pNode= pNode->GetNext();
01503     }
01504 
01505     if (pOpenDocument != NULL)
01506     {
01507         // Make sure it really is one of ours.
01508         ERROR3IF( !pOpenDocument->IsKindOf( CLASSINFO(CCamDoc) ),
01509                     _T("Not a CCamDoc in CCamApp::OpenDocumentFile") );
01510 
01511         wxList&         lstViews( pOpenDocument->GetViews() );
01512         wxNode*         pNode = lstViews.GetFirst();
01513         if( NULL != pNode )
01514         {
01515             // Get the first view.
01516             wxView*     pView = (wxView*)pNode->GetData();
01517             wxMDIChildFrame* pFrame = (wxMDIChildFrame*)pView->GetFrame();
01518             
01519             // Now deal with the view window.
01520             if (pFrame != NULL)
01521             {
01522                 // Run a message box to find out what the user wants to do on trying
01523                 // to load a document that is already loaded.  To begin, if we can't
01524                 // find a document template just bring the view to the front.
01525                 if (pBestTemplate == NULL)
01526                 {
01527                     pFrame->Activate();
01528                 }
01529                 else
01530                 {
01531                     // If the document is modified then we may have to ask the user what they
01532                     // want to do, ie. revert to original, load copy, do nothing.
01533                     INT32 nResult;
01534                     if (pOpenDocument->IsModified())
01535                     {
01536                         // OK, we have a modified document.  Run the message box to find out what
01537                         // the user wants to do.
01538                         nResult = InformWarning( _R(IDE_DOC_ALREADY_OPEN),
01539                                                 _R(IDS_REVERT_BTN), _R(IDS_DETACH_BTN), _R(IDS_CANCEL), 0,
01540                                                 2, 3);
01541                     }
01542                     else
01543                     {
01544                         // If the document isn't modified then force a "load copy".
01545                         // no if the document is already loaded just keep the view we have (sjk 3/2/00)
01546                         nResult = 3;
01547                     }
01548 
01549                     switch (nResult)
01550                     {
01551                     case 1:
01552                     {
01553                         // REVERT.  Reload the already-open doc, discarding unsaved changes.
01554                         ((CCamDoc*) pOpenDocument)->SetModified(FALSE);
01555                         pOpenDocument->OnCloseDocument();
01556                         pNewDoc = pBestTemplate->CreateDocument( szPath );
01557                         goto PerformLoad;
01558                     }
01559 
01560                     case 2:
01561                     {
01562                         // DETACH.  Load the doc as an "untitled" one, making sure it won't
01563                         // save over the already-open doc.
01564                         wxDocument* pCopyDoc = pBestTemplate->CreateDocument( szPath );
01565                         if (pCopyDoc != NULL)
01566                         {
01567                             // We managed to load the doc to detach, so now we detach it.
01568                             // To do this we set its path to nothing, after saving the
01569                             // original path.
01570                             ((CCamDoc*) pCopyDoc)->SetOriginalPath(szPath);
01571                             ((CCamDoc*) pCopyDoc)->SetPathNameEmpty();
01572                             ((CCamDoc*) pCopyDoc)->SetCopy(TRUE);
01573 
01574                             goto PerformLoad;
01575                         }
01576                     #ifdef _DEBUG
01577                         else
01578                         {
01579                             // Oh no, we failed to load the detached doc, so we have to
01580                             // fail this one.
01581                             TRACEUSER("JustinF", _T("Couldn't load doc to detach!\n") );
01582                             pFrame->Activate();
01583                         }
01584                     #endif                      
01585                         return NULL;
01586                     }
01587 
01588                     case 3:
01589                         // CANCEL.  Don't load, just bring the already-open doc to the front.
01590                         pFrame->Activate();
01591                         break;
01592 
01593                     default:
01594                         ERROR3( _T("Bad return val from message box in CCamApp::OpenDocumentFile") );
01595                         break;
01596                     }
01597                 }
01598             }
01599             else
01600                 TRACE0( _T("Error: Can not find a frame for document to activate.\n") );
01601         }
01602         else
01603         {
01604             TRACE0( _T("Error: Can not find a view for document to activate.\n") );
01605         }
01606 
01607         return pOpenDocument;
01608     }
01609 
01610     if (pBestTemplate == NULL)
01611     {
01612         String_256      strReport( _R(AFX_IDP_FAILED_TO_OPEN_DOC) );
01613         wxMessageBox( (PCTSTR)strReport );
01614         return NULL;
01615     }
01616 
01617     pNewDoc =  pBestTemplate->CreateDocument( szPath );
01618 
01619 PerformLoad:
01620     if( NULL == pNewDoc )
01621         return NULL;
01622 
01623     pNewDoc->SetDocumentName( pBestTemplate->GetDocumentName() );
01624     pNewDoc->SetDocumentTemplate( pBestTemplate );
01625     if( !pNewDoc->OnOpenDocument( szPath ) )
01626     {
01627         pNewDoc->DeleteAllViews();
01628         pNewDoc = NULL;
01629     }
01630 
01631     return pNewDoc;
01632 }
01633 
01634 
01635 
01636 /********************************************************************************************
01637 
01638 >   BOOL CCamApp::MakeDocumentNative(CDocument* pDoc, PathName* Path)
01639 
01640     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01641     Created:    14/2/95
01642     Inputs:     pDoc - The document to test and change
01643                 Path - the path of the original document name
01644     Outputs:    Path - This will have the extension modified if the function returned TRUE
01645     Returns:    TRUE if it changed the document, FALSE if it did not
01646     Purpose:    If you attemp to open a BMP or any other non native file, it will have a
01647                 bad document name (ending in .bmp or whatever, instead of .art). It also
01648                 causes problems when pressing save, as the original non native file can
01649                 be overwritten with a native file version. This makes sure that the user
01650                 will always be asked where they want to save it when it comes to saving
01651                 time by throwing away the know path info.
01652     SeeAlso:    CCamApp::OnRecentFile; CCamApp::OnFileOpen
01653 
01654 ********************************************************************************************/
01655 
01656 BOOL CCamApp::MakeDocumentNative( wxDocument* pDoc, PathName* Path )
01657 {
01658     // Only bother if the was actually a document to process
01659     if (pDoc==NULL)
01660         return FALSE;
01661 
01662     // Set the extension of the file to be .xar
01663     String_256 Extension( _R(IDS_DEFAULT_EXTENSION) );
01664     String_256 OldExtension = Path->GetType();
01665     // make sure they are of the same case
01666     Extension.toLower();
01667     OldExtension.toLower();
01668 #if NEW_NATIVE_FILTER
01669     String_256 NewExtension(_R(IDS_DEFAULT_EXTENSION));
01670     NewExtension.toLower();
01671     // see if the extension is .xar or .cxn
01672     if (Extension != OldExtension && OldExtension != NewExtension)
01673 #else
01674     // see if the extension is .xar
01675     if (Extension != OldExtension)
01676 #endif
01677     {
01678         Path->SetType(Extension);
01679 
01680         // Find out some of the details about the filename
01681         String_256 FileName = Path->GetFileName();
01682 
01683         // Set the title of and path of the document
01684         // we set the path to blank, so that we will always be prompted for a real filename
01685         ((CCamDoc*)pDoc)->SetTitle( FileName );
01686         pDoc->SetFilename( FileName, true );
01687         ((CCamDoc*)pDoc)->SetPathNameEmpty();
01688 
01689         TRACEUSER( "luke", _T("New name %s"), PCTSTR(FileName) );
01690 
01691         // Tell 'em we changed things
01692         return TRUE;
01693     }
01694 
01695     // Nothing changed
01696     return FALSE;
01697 }
01698 
01699 
01700 
01701 /********************************************************************************************
01702  *
01703 
01704 >   void CCamApp::OnRecentFile(INT32 RecentFileNumber)
01705 
01706     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01707     Created:    3/1/95
01708     Inputs:     RecentFileNumber - The number of the file in the Recent File list to open
01709     Returns:    TRUE if it loaded the file ok, FALSE if it failed
01710     Purpose:    Loads in one of the recently opened documents that are in the 'Recent File
01711                 List' near the bottom of the File Menu.
01712 
01713 ********************************************************************************************/
01714 
01715 bool CCamApp::OnRecentFile(INT32 RecentFileNumber)
01716 {
01717     wxFileHistory*  pFileHist = m_docManager->GetFileHistory();
01718 
01719     if( RecentFileNumber < INT32(pFileHist->GetCount()) )
01720     {
01721         wxString    FileName( pFileHist->GetHistoryFile( RecentFileNumber ) );
01722 
01723         // Get the App to open the File
01724         if (!FileName.IsEmpty())
01725         {
01726             // See if we got a document out of the deal
01727             wxDocument* pDoc = m_docManager->CreateDocument( FileName, wxDOC_SILENT );
01728             if( pDoc != NULL )
01729                 return true;
01730         }
01731     }
01732 
01733     // Failed to find an entry for this item
01734     return false;   
01735 }
01736 
01737 
01738 
01739 /********************************************************************************************
01740 
01741 >   BOOL CCamApp::GetRecentFileText(INT32 Index, String_256* Text)
01742 
01743     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01744     Created:    4/1/95
01745     Inputs:     Index - The index into the recent file list that we are interested in
01746     Outputs:    Text - the file name of the recent file. This will be abbreviated it is
01747                 too long. This param is only changed if this function returns TRUE.
01748     Returns:    TRUE if it found and entry, FALSE if it did not
01749     Purpose:    Gets the text suitable for the menu text for a given recent file. If there
01750                 is an available file the Text param will hold the abbreviated filename
01751                 (eg. c:\...\blobby.art). If the function returns FALSE, then the Text param
01752                 is left alone.
01753 
01754 ********************************************************************************************/
01755 
01756 bool CCamApp::GetRecentFileText(INT32 Index, String_256* pszText)
01757 {
01758     wxFileHistory*      pFileHist = m_docManager->GetFileHistory();
01759 
01760     if( Index < INT32(pFileHist->GetCount()) )
01761     {
01762         wxFileName  deconstruct( pFileHist->GetHistoryFile( Index ) );
01763         *pszText = deconstruct.GetFullName();
01764         return true;
01765     }
01766 
01767     // Failed to find an entry for this item
01768     return false;   
01769 }
01770 
01771 
01772 void CCamApp::DoAboutBox()
01773 {
01774     wxString            strMessage;
01775 
01776 #if defined(__WXMSW__)
01777     strMessage = wxString::Format( wxT("Xara Xtreme\nVersion: %s\nCDraw Version: %d.%03d\nUsage: XaraLX.exe [xar-file...]"), 
01778         g_pszAppVersion, HIWORD(GDraw_GetVersion()), LOWORD(GDraw_GetVersion()) );
01779 #else
01780 #if FALSE == wxUSE_UNICODE
01781     TCHAR*          pszCDrawVer = GDraw_GetSvnVersion();
01782 #else
01783     TCHAR           pszCDrawVer[32];
01784     camMbstowcs( pszCDrawVer, GDraw_GetSvnVersion(), 31 );
01785 #endif
01786     strMessage = wxString::Format( wxT("Xara Xtreme\nVersion: %s (%s)\nBuild date: %s\nBuilt against: " wxVERSION_STRING "\n" /*"wxWidgets linked to %s\n" */ "Usage: xaralx [xar-file...]"), 
01787         g_pszAppVersion, g_pszSvnVersion, CAMELOT_BUILD_DATE /*,_T("Unknown")*/ );
01788 #endif
01789 
01790     (void)wxMessageBox( strMessage, wxT("About Xara Xtreme") );
01791 }
01792 
01793 StringBase& CCamApp::GetResourceDirectory()
01794 {
01795     return m_strResourceDirPath;
01796 }
01797 
01798 void CCamApp::GiveActiveCanvasFocus()
01799 {
01800     CCamView* pView = dynamic_cast<CCamView*>( m_docManager->GetCurrentView() );
01801     if( NULL != pView )
01802     {
01803         pView->Activate( true );
01804         pView->GetRenderWindow()->SetFocus();
01805     }
01806 }
01807 
01808 /***************************************************************************************************************************/
01809 //
01810 // The following is class is needed to ensure that the file menu is removed
01811 // from the file histroy menu list.
01812 //
01813 class CCamDocMDIChildFrame : public wxDocMDIChildFrame
01814 {
01815 public :
01816     CCamDocMDIChildFrame(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id,
01817         const wxString& title, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
01818     /* TYPENOTE: Correct */ long type = wxDEFAULT_FRAME_STYLE, const wxString& name = wxT("frame"))
01819         : wxDocMDIChildFrame(doc,view,frame,id,title,pos,size,type,name)
01820     { }
01821 
01822     virtual bool Destroy()
01823     { 
01824 #if defined(FILELIST)
01825         wxDocManager* pDocMan = wxGetApp().GetDocumentManager();
01826         if ( pDocMan && GetMenuBar() && GetMenuBar()->GetMenu(0) )
01827             pDocMan->FileHistoryRemoveMenu(GetMenuBar()->GetMenu(0));
01828 #endif
01829         return wxDocMDIChildFrame::Destroy(); 
01830     }
01831 };
01832 
01833 /***************************************************************************************************************************/
01834 /*
01835  * Centralised code for creating a document frame.
01836  * Called from view.cpp, when a view is created.
01837  */
01838 
01839 wxMDIChildFrame *CCamApp::CreateChildFrame(wxDocument *doc, wxView *view)
01840 {
01842     CCamDocMDIChildFrame *subframe = 
01843         new CCamDocMDIChildFrame(doc, view, GetMainFrame(), wxID_ANY, _T("Child Frame"), 
01844             wxPoint(10, 10), wxSize(600, 450),
01845             wxDEFAULT_FRAME_STYLE |
01846             wxNO_FULL_REPAINT_ON_RESIZE);
01847 
01848 #ifdef __WXMSW__
01849     subframe->SetIcon(wxString(_T("chart")));
01850 #endif
01851 #ifdef __X__
01852     subframe->SetIcon(wxIcon(_T("doc.xbm")));
01853 #endif
01854 
01855 #if !defined(XARA_MENUGEN)
01856 
01857     wxMenu*    file_menu = new wxMenu;
01858     wxMenu*    edit_menu = new wxMenu;
01859     wxMenu*    zoom_menu = new wxMenu;
01860     wxMenu* quality_menu = new wxMenu;
01861     wxMenu*   other_menu = new wxMenu;
01862     wxMenu*    help_menu = new wxMenu;
01863 
01864     file_menu->Append( wxID_NEW,                        wxT("&New..."           ) );
01865     file_menu->Append( wxID_OPEN,                       wxT("&Open..."          ) );
01866     file_menu->Append( wxID_CLOSE,                      wxT("&Close"            ) );
01867     file_menu->Append( wxID_SAVE,                       wxT("&Save"             ) );
01868     file_menu->Append( wxID_SAVEAS,                     wxT("Save &As..."       ) );
01869 
01870 #if defined(FILELIST)
01871     wxMenu* pRecentFilesMenu = new wxMenu;
01872     m_docManager->FileHistoryUseMenu(pRecentFilesMenu);
01873     m_docManager->FileHistoryAddFilesToMenu(pRecentFilesMenu);
01874 
01875     file_menu->AppendSeparator();
01876     file_menu->Append( -1,                              wxT("&Recent files"),   pRecentFilesMenu );
01877 #endif
01878 
01879     file_menu->AppendSeparator();
01880     file_menu->Append( wxID_PRINT,                      wxT("&Print..."         "\tCtrl+P") );
01881     file_menu->Append( wxID_PRINT_SETUP,                wxT("Print &Setup..."   ) );
01882     file_menu->Append( wxID_PREVIEW,                    wxT("Print Pre&view"    ) );
01883     file_menu->AppendSeparator();
01884     file_menu->Append( wxID_EXIT,                       wxT("E&xit"             ) );
01885 
01886     edit_menu->Append( wxID_UNDO,                       wxT("&Undo"             ) );
01887     edit_menu->Append( wxID_REDO,                       wxT("&Redo"             ) );
01888 //  edit_menu->AppendSeparator();
01889 //  edit_menu->Append( DOCVIEW_CUT, _T("&Cut last segment") );
01890     if( NULL != doc->GetCommandProcessor() )
01891         doc->GetCommandProcessor()->SetEditMenu( edit_menu );
01892 
01893     zoom_menu->Append( _R(DOCVIEW_ZOOMIN),              wxT("Zoom &in"          ) );
01894     zoom_menu->Append( _R(DOCVIEW_ZOOMOUT),             wxT("Zoom &out"         ) );
01895     zoom_menu->Append( _R(DOCVIEW_ZOOMDRAWING),         wxT("Zoom to &drawing"  ) );
01896     zoom_menu->Append( _R(DOCVIEW_ZOOMSPREAD),          wxT("Zoom to &page"     ) );
01897     zoom_menu->Append( _R(DOCVIEW_ZOOMPREVIOUS),        wxT("Previous &zoom"    ) );
01898 
01899     quality_menu->Append( _R(DOCVIEW_QUALITYANTIALIASED),   wxT("&Antialiased"  ),  wxT(""),wxITEM_RADIO );
01900     quality_menu->Append( _R(DOCVIEW_QUALITYNORMAL),        wxT("&Normal"       ),  wxT(""),wxITEM_RADIO );
01901     quality_menu->Append( _R(DOCVIEW_QUALITYSIMPLE),        wxT("&Simple"       ),  wxT(""),wxITEM_RADIO );
01902     quality_menu->Append( _R(DOCVIEW_QUALITYOUTLINE),       wxT("&Outline"      ),  wxT(""),wxITEM_RADIO );
01903 
01904     other_menu->Append( _R(DOCVIEW_BACKGROUNDRENDER),       wxT("&Background render"),  wxT(""),wxITEM_CHECK );
01905     other_menu->Append( _R(DOCVIEW_CACHING),                wxT("&Caching"),                wxT(""),wxITEM_CHECK );
01906 #ifdef __WXGTK__
01907     other_menu->Append( _R(DOCVIEW_DOUBLEBUFFER),           wxT("&Double buffer\tHmmm"),        wxT(""),wxITEM_CHECK );
01908 #endif
01909 //#if _DEBUG
01910     other_menu->Append( _R(DOCVIEW_TIMEREDRAW),             wxT("&Time redraw"      "\tCtrl+Shift+T") );
01911 //#endif
01912 //#if _DEBUG
01913     other_menu->Append( _R(DOCVIEW_BLOBBYDLG),              wxT("B&lobby Dialog"    "\tHmmm") );
01914     other_menu->Append( _R(DOCVIEW_BLOBBYBAR),              wxT("Blobb&y Bar"       "\tHmmm") );
01915     other_menu->Append( _R(DEBUG_TREEVIEWDLG),              wxT("Document Tree"     "\tHmmm") );
01916 //#endif
01917 
01918 
01919     other_menu->Append( _R(IDD_BUTTBAR_STATUS),             _T("Status Bar"         "\tHmmm"), wxT(""),wxITEM_CHECK  );
01920     other_menu->Append( _R(IDD_BUTTBAR_GENERAL),            _T("General Bar"        "\tHmmm"), wxT(""),wxITEM_CHECK );
01921     other_menu->Append( _R(IDD_BUTTBAR_IMAGESETTING),       _T("ImageSetting Bar"   "\tHmmm"), wxT(""),wxITEM_CHECK  );
01922     other_menu->Append( _R(IDD_BUTTBAR_WINDOW),             _T("Window Bar"         "\tHmmm"), wxT(""),wxITEM_CHECK  );
01923     other_menu->Append( _R(IDD_BUTTBAR_ARRANGE),            _T("Arrange Bar"        "\tHmmm"), wxT(""),wxITEM_CHECK  );
01924     other_menu->Append( _R(IDD_BUTTBAR_EDIT),               _T("Edit Bar"           "\tHmmm"), wxT(""),wxITEM_CHECK  );
01925     other_menu->Append( _R(IDD_BUTTBAR_FILE),               _T("File Bar"           "\tHmmm"), wxT(""),wxITEM_CHECK  );
01926     other_menu->Append( _R(IDD_BUTTBAR_GALLERIES),          _T("Galleries Bar"      "\tHmmm"), wxT(""),wxITEM_CHECK  );
01927     other_menu->Append( _R(IDD_BUTTBAR_STANDARD),           _T("Standard Bar"       "\tHmmm"), wxT(""),wxITEM_CHECK  );
01928     other_menu->Append( _R(IDD_BUTTBAR_TOOLBAR),            _T("Toolbar Bar"        "\tHmmm"), wxT(""),wxITEM_CHECK  );
01929     other_menu->Append( _R(IDD_BUTTBAR_ANIMATION),          _T("Animation Bar"      "\tHmmm"), wxT(""),wxITEM_CHECK  );
01930     other_menu->Append( _R(IDD_BUTTBAR_FEATHER),            _T("Feather Bar"        "\tHmmm"), wxT(""),wxITEM_CHECK  );
01931 
01932 
01933     help_menu->Append( _R(DOCVIEW_ABOUT),                   wxT("&About..."         "\tF1"));
01934 
01935     wxMenuBar* menu_bar = new wxMenuBar;
01936 
01937     menu_bar->Append(   file_menu, _T("File"    ));
01938     menu_bar->Append(   edit_menu, _T("Edit"    ));
01939     menu_bar->Append(   zoom_menu, _T("Zoom"    ));
01940     menu_bar->Append(quality_menu, _T("Quality"));
01941     menu_bar->Append(  other_menu, _T("Other"   ));
01942     menu_bar->Append(   help_menu, _T("Help"    ));
01943 
01944     // Associate the menu bar with the frame
01945     subframe->SetMenuBar(menu_bar);
01946 #endif
01947 
01948     // Luke: This seems to be needed to enable accelerator on GTK
01949     // Gavin: No, this is a bad idea. It mucks up the creation of the
01950     // "Window" submenu, and perhaps other things as well.
01951 //  subframe->SetFocus();
01952 
01953 #if WX_ACCEL
01954     wxAcceleratorEntry entries[1];
01955     entries[ 0].Set(wxACCEL_CTRL|wxACCEL_SHIFT, 'T',    _R(DOCVIEW_TIMEREDRAW)          );
01956 /*  //
01957     // Not necessary since the accelerator is automatically
01958     // built from the menu accelerator text.
01959     //
01960     entries[ 1].Set(wxNORMAL,                   '=',    _R(DOCVIEW_ZOOMIN)              );
01961     entries[ 2].Set(wxNORMAL,                   '+',    _R(DOCVIEW_ZOOMIN)              );
01962     entries[ 3].Set(wxNORMAL,                   '-',    _R(DOCVIEW_ZOOMOUT)             );
01963     entries[ 4].Set(wxNORMAL,                   'D',    _R(DOCVIEW_ZOOMDRAWING)         );
01964     entries[ 5].Set(wxNORMAL,                   'P',    _R(DOCVIEW_ZOOMSPREAD)          );
01965     entries[ 6].Set(wxNORMAL,                   'Z',    _R(DOCVIEW_ZOOMPREVIOUS)        );
01966     entries[ 7].Set(wxNORMAL,                   '1',    _R(DOCVIEW_QUALITYOUTLINE)      );
01967     entries[ 8].Set(wxNORMAL,                   '2',    _R(DOCVIEW_QUALITYSIMPLE)       );
01968     entries[ 9].Set(wxNORMAL,                   '3',    _R(DOCVIEW_QUALITYNORMAL)       );
01969     entries[10].Set(wxNORMAL,                   '4',    _R(DOCVIEW_QUALITYANTIALIASED)  );
01970     entries[11].Set(wxNORMAL,                   'B',    _R(DOCVIEW_BACKGROUNDRENDER)    );
01971     entries[12].Set(wxNORMAL,                   'B',    _R(DOCVIEW_CACHING)             );
01972 */  wxAcceleratorTable accel(1,entries);
01973     subframe->SetAcceleratorTable(accel);
01974 #else
01975     // We don't want auto-accelerators, this is done using our hotkeys
01976     // I don't know how to do this yet, but I'm looking....
01977 #endif
01978 
01979     return subframe;
01980 }
01981 
01982 /********************************************************************************************
01983 
01984 >   static DialogManager* CCampApp::GetDlgManager()
01985 
01986     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01987     Created:    19/8/93
01988     Inputs:     -
01989     Outputs:    -
01990     Returns:    A pointer to the dialog manager
01991     Purpose:    For obtaining a pointer to the dialog manager
01992     Errors:     -
01993     SeeAlso:    -
01994 
01995 ********************************************************************************************/
01996             
01997 DialogManager *CCamApp::GetDlgManager()
01998 {
01999     return( &m_DlgMgr ); 
02000 }
02001 
02002 // Functions to Enable/Disable system functionality 
02003 
02004 /********************************************************************************************
02005 
02006 >   void CCamApp::DisableSystem(CWindowID WindowID = NULL)
02007 
02008     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02009     Created:    28/10/93
02010     Inputs:     -
02011     Outputs:    -
02012     Returns:    -
02013     Purpose:    This function sets a flag which disables all rendering and processing of user 
02014                 messages in the system.  
02015     Errors:     -
02016     SeeAlso:    -
02017 
02018 ********************************************************************************************/
02019 
02020 void CCamApp::DisableSystem(CWindowID WindowID /*=NULL*/)
02021 {
02022 // RALPH
02023 #ifdef RALPH
02024     return;
02025 #endif
02026 
02027     // Disable camelot's main window. This disables the menu bar, button bar etc. 
02028     // It does not disable the tool bar however. This will be disabled in the tool bar code 
02029     // by testing the DisableSystem flag. 
02030     wxApp              *pWinApp;
02031     wxWindow           *pWnd;
02032 
02033     if ( ( pWinApp = &AfxGetApp() ) != NULL )       // Note assignment using = not == on both lines
02034                                                     // Don't disabled if the TLW is the error box we
02035                                                     // are disabling in favour of
02036         if ( (( pWnd = pWinApp->GetTopWindow() ) !=NULL ) && (pWnd != WindowID))
02037             pWnd->Enable(FALSE);                    // Only perform operation if no pointers are NULL
02038     s_bIsDisabled = true; // The flags value will be tested in the rendering and tool bar
02039                           // code etc. When TRUE functionality will be disabled.    
02040 }
02041 
02042 /********************************************************************************************
02043 
02044 >   void CCamApp::EnableSystem(void)  
02045 
02046     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02047     Created:    28/10/93
02048     Inputs:     -
02049     Outputs:    -
02050     Returns:    -
02051     Purpose:    This function restores system functionality. 
02052     Errors:     An ENSURE failure will occur if the DisableSys flag was not set when this 
02053                 function was called. 
02054     SeeAlso:    CCamApp::DisableSystem
02055 
02056 ********************************************************************************************/
02057 
02058 void CCamApp::EnableSystem()  
02059 {
02060     wxApp              *pWinApp;
02061     wxWindow           *pWnd;
02062 
02063     ENSURE( s_bIsDisabled, "Trying to enable system which is already enabled" );
02064     // Enable Camelot's main window. 
02065     if ( ( pWinApp = &AfxGetApp() ) != NULL )       // Note assignment using = not == on both lines
02066         if ( ( pWnd = pWinApp->GetTopWindow() ) !=NULL )
02067             pWnd->Enable(TRUE);                     // Only perform operation if no pointers are NULL
02068     s_bIsDisabled = false; // Enable system functionality
02069 }
02070 
02071 #if defined(__WXMSW__)
02072 
02073 // each element in here corresponds to something in the Winver enumerated type, used
02074 // in the inline functions in camelot.h
02075 BOOL                    WinArray[2];
02076 
02077 #endif
02078 
02079 
02080 /*******************************************************************************************/
02081 
02082 void CCamApp::OnIdle( wxIdleEvent &event )
02083 {
02084 //  TRACEUSER("Gerry", _T("CCamApp::OnIdle\n"));
02085 
02086     if ( IsDisabled() || PrintMonitor::IsPrintingNow() )
02087     {
02088 //      TRACEUSER("Gerry", _T("Disabled - Is this a bad thing????????\n"));
02089         event.Skip();
02090         return;
02091     }
02092 
02093     // First thing we will clean up any "temporary" DCs
02094 //  CCDC::CleanUpDCs();
02095 
02096     ControlList::Idle();
02097 
02098     if ( Camelot.OnIdle(true) )
02099     {
02100         event.RequestMore();
02101     }
02102 
02103 //  TRACEUSER("Gerry", _T("MoreRequested = %s\n"), event.MoreRequested() ? _T("true") : _T("false"));
02104 
02105     // We *MUST* call Skip() here or you can't exit the program!
02106     event.Skip();
02107 }
02108 
02109 /*******************************************************************************************/
02110 
02111 void CCamApp::OnTimer( wxTimerEvent& WXUNUSED(event) )
02112 {
02113     if (!PrintMonitor::IsPrintingNow() )
02114     {
02115 //      TRACEUSER("Gerry", _T("Disabled - Is this a bad thing????????\n"));
02116         //
02117         // This should also exit the while loop if there are messages in the
02118         // message queue.
02119         //
02120         while ( Camelot.ServiceRendering() )
02121             ;
02122     }
02123 PORTNOTE("other","CCamApp::OnTimer - needs completing")
02124 }
02125 
02126 /*******************************************************************************************/
02127 
02128 void CCamApp::OnHelpIndex()
02129 {
02130     // Get the locale id
02131     wxString    strLocale( setlocale( LC_MESSAGES, NULL ), wxConvUTF8 );
02132     INT32       ordSep = strLocale.Find( _T('_' ) );
02133     if ( -1 != ordSep )
02134         strLocale = strLocale.Left( ordSep );
02135     TRACEUSER( "jlh92", _T("Locale = %s\n"), PCTSTR(strLocale) );
02136     
02137     // Locale C is considered a synonym for en
02138     if( strLocale == _T("C") )
02139         strLocale = _T("en");
02140 
02141     // Check the help dir exists, if not bomb out
02142     wxString    strHelpPath( (TCHAR*)m_strResourceDirPath );
02143     strHelpPath += _T("/doc/");
02144     TRACEUSER( "jlh92", _T("Using filter discovery directory \"%s\"\n"), PCTSTR(strHelpPath + strLocale) );
02145     if( wxDir::Exists( strHelpPath + strLocale ) )
02146         strHelpPath += strLocale + _T("/");
02147     else
02148     {
02149         if( wxDir::Exists( strHelpPath + _T("en") ) )
02150             strHelpPath += _T("en/");
02151 #if defined(_DEBUG)
02152         else
02153         {
02154             // We'll try default location under debug to make life easier
02155             strHelpPath = _T("/usr/share/xaralx/doc/en/");
02156             TRACEUSER( "jlh92", _T("Try = \"%s\"\n"), PCTSTR(strHelpPath) );
02157         }
02158 #endif
02159     }
02160 
02161     // Build full path
02162     wxString strUrl;
02163     strUrl = strHelpPath;
02164     strUrl += _T("xaralx.htm");
02165     if (!wxFile::Exists(strUrl))
02166     {
02167         // Complete failure to find any local help files
02168         // So go to the web site...
02169         strUrl = _T("http://www.xaralx.org");
02170     }
02171     else
02172     {
02173         // Build the complete URL and launch browser
02174         strUrl.Prepend(_T("file://"));
02175     }
02176 
02177     LaunchWebBrowser(strUrl);
02178 
02179 }
02180 
02181 
02182 /********************************************************************************************
02183 
02184 >   static BOOL CCamApp::LaunchWebBrowser(const wxString& strUrl)
02185 
02186     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02187     Created:    22/May/2006
02188     Inputs:     -
02189     Outputs:    -
02190     Returns:    -
02191     Purpose:    Launch a web browser referring to a given URL
02192 
02193 ********************************************************************************************/
02194 
02195 BOOL CCamApp::LaunchWebBrowser(const wxString& strUrl)
02196 {
02197     // --------------------------------------------------------------------------------------
02198     // Attempt to launch common browsers to cope with our rich, Javascripted, HTML help files
02199     //
02200     // There are long-winded reasons for doing it this way which were discussed on the
02201     // dev@xaraxtreme.org mailing list.
02202     //
02203     BOOL ok;
02204 
02205     // http://portland.freedesktop.org/wiki/TaskOpenURL
02206     // ok = LaunchBrowserApp(_T("xdg-open"), strUrl);
02207     // if (ok) return ok;
02208 
02209     // http://lists.freedesktop.org/pipermail/xdg/2004-August/004489.html
02210     ok = LaunchBrowserApp(_T("desktop-launch"), strUrl);
02211     if (ok) return ok;
02212 
02213     ok = LaunchBrowserApp(_T("gnome-open"), strUrl);
02214     if (ok) return ok;
02215 
02216     ok = LaunchBrowserApp(_T("htmlview"), strUrl);
02217     if (ok) return ok;
02218 
02219     ok = LaunchBrowserApp(_T("firefox"), strUrl);
02220     if (ok) return ok;
02221 
02222     ok = LaunchBrowserApp(_T("mozilla"), strUrl);
02223     if (ok) return ok;
02224 
02225     ok = LaunchBrowserApp(_T("konqueror"), strUrl);
02226     if (ok) return ok;
02227 
02228     ok = LaunchBrowserApp(_T("gnome-www-browser"), strUrl);
02229     if (ok) return ok;
02230 
02231     ok = LaunchBrowserApp(_T("epiphany"), strUrl);
02232     if (ok) return ok;
02233 
02234     ok = LaunchBrowserApp(_T("opera"), strUrl);
02235     if (ok) return ok;
02236 
02237     ok = LaunchBrowserApp(_T("iexplore"), strUrl);
02238     if (ok) return ok;
02239 
02240     ok = LaunchBrowserApp(_T("safari"), strUrl);
02241     if (ok) return ok;
02242 
02243     ok = wxLaunchDefaultBrowser(strUrl);
02244 
02245     return ok;
02246 }
02247 
02248 
02249 BOOL CCamApp::LaunchBrowserApp(const wxString& strAppName, wxString strCommand)
02250 {
02251     strCommand.Prepend(_T(" "));
02252     strCommand.Prepend(strAppName);
02253 
02254     CamLaunchProcess* plp = new CamLaunchProcess();
02255     if (plp==NULL)
02256         return FALSE;
02257 
02258     BOOL ok = plp->Execute(strCommand);
02259 
02260     if (ok)
02261     {
02262         // Let this process run free!
02263         plp->Disconnect();
02264 //      delete plp;                             // This object will allegedly delete itself when the process dies
02265     }
02266     else
02267     {
02268         // Make sure we don't leave any zombie processes lying around
02269         wxKillError e = plp->Terminate();       // This should result in a call to OnTerminate
02270         TRACEUSER("Phil", _T("Terminating bad process returned %d\n"), e);
02271 //      delete plp;                             // This object will allegedly delete itself when the process dies
02272     }
02273 
02274     return ok;
02275 }
02276 
02277 /***************************************************************************************************************************/
02278 
02279 
02281 
02282 #if 0
02283 
02284 //
02285 // This code needs to be put into wx\common\menucmn.cpp
02286 //
02287 // The accelerators of menu strings are decoded and accelerators are
02288 // automatically built from them. This works well most of the time
02289 // but numeric keypad accelerators must be added in a rather ugly 
02290 // format such as "Ctrl+KP_ADD". This code enables them to be included
02291 // in a format such as "Ctrl+Num +", ie Num (and Numpad) are used as 
02292 // modifiers in the same way as Shift, Ctrl and Alt.
02293 //
02294 // Could probably do with further improvement.
02295 //
02296 
02297 static inline bool CompareAccelString(const wxString& str, const wxChar *accel)
02298 {
02299 #if wxUSE_INTL
02300     return str == accel || str == wxGetTranslation(accel);
02301 #else
02302     return str == accel;
02303 #endif
02304 }
02305 
02306  wxAcceleratorEntry *wxGetAccelFromString(const wxString& label)
02307 {
02308     // wxPrintf( wxT("label %s\n"), label.c_str() );
02309 
02310     // check for accelerators: they are given after '\t'
02311     INT32 posTab = label.Find(wxT('\t'));
02312     if ( posTab != wxNOT_FOUND ) {
02313         // parse the accelerator string
02314         INT32 keyCode = 0;
02315         INT32 accelFlags = wxACCEL_NORMAL;
02316         wxString current;
02317         bool bNumPad = false;
02318         for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) {
02319             if ( (label[n] == '+') || (label[n] == '-') ) {
02320                 if ( CompareAccelString(current, wxTRANSLATE("ctrl")) )
02321                     accelFlags |= wxACCEL_CTRL;
02322                 else if ( CompareAccelString(current, wxTRANSLATE("alt")) )
02323                     accelFlags |= wxACCEL_ALT;
02324                 else if ( CompareAccelString(current, wxTRANSLATE("shift")) )
02325                     accelFlags |= wxACCEL_SHIFT;
02326                 else if ( CompareAccelString(current, wxTRANSLATE("numpad")) ||
02327                           CompareAccelString(current, wxTRANSLATE("num")) )
02328                     bNumPad = true;
02329                 else {
02330                     // we may have "Ctrl-+", for example, but we still want to
02331                     // catch typos like "Crtl-A" so only give the warning if we
02332                     // have something before the current '+' or '-', else take
02333                     // it as a literal symbol
02334                     if ( current.empty() )
02335                     {
02336                         current += label[n];
02337 
02338                         // skip clearing it below
02339                         continue;
02340                     }
02341                     else
02342                     {
02343                         wxLogDebug(wxT("Unknown accel modifier: '%s'"),
02344                                    current.c_str());
02345                     }
02346                 }
02347 
02348                 current.clear();
02349             }
02350             else {
02351                 current += (wxChar) wxTolower(label[n]);
02352             }
02353         }
02354 
02355         if ( current.empty() ) {
02356             wxLogDebug(wxT("No accel key found, accel string ignored."));
02357         }
02358         else {
02359             if ( current.Len() == 1 && !bNumPad ) {
02360                 // it's a letter
02361                 keyCode = current[0U];
02362 
02363                 // Only call wxToupper if control, alt, or shift is held down,
02364                 // otherwise lower case accelerators won't work.
02365                 if (accelFlags != wxACCEL_NORMAL) {
02366                     keyCode = wxToupper(keyCode);
02367                 }
02368             }
02369             else {
02370                 // is it a function key?
02371                 if ( current[0U] == 'f' && wxIsdigit(current[1U]) &&
02372                      (current.Len() == 2 ||
02373                      (current.Len() == 3 && wxIsdigit(current[2U]))) ) {
02374                     keyCode = CAMKEY(F1) + wxAtoi(current.c_str() + 1) - 1;
02375                 }
02376                 else {
02377                     // several special cases
02378                     current.MakeUpper();
02379                     if ( current == wxT("DEL") )
02380                         keyCode = CAMKEY(DELETE);
02381                     else if ( current == wxT("DELETE") )
02382                         keyCode = CAMKEY(DELETE);
02383                     else if ( current == wxT("BACK") )
02384                         keyCode = CAMKEY(BACK);
02385                     else if ( current == wxT("INS") )
02386                         keyCode = CAMKEY(INSERT);
02387                     else if ( current == wxT("INSERT") )
02388                         keyCode = CAMKEY(INSERT);
02389                     else if ( current == wxT("ENTER") || current == wxT("RETURN") )
02390                         keyCode = CAMKEY(RETURN);
02391                     else if ( current == wxT("PGUP") )
02392                         keyCode = CAMKEY(PRIOR);
02393                     else if ( current == wxT("PGDN") )
02394                         keyCode = CAMKEY(NEXT);
02395                     else if ( current == wxT("LEFT") )
02396                         keyCode = CAMKEY(LEFT);
02397                     else if ( current == wxT("RIGHT") )
02398                         keyCode = CAMKEY(RIGHT);
02399                     else if ( current == wxT("UP") )
02400                         keyCode = CAMKEY(UP);
02401                     else if ( current == wxT("DOWN") )
02402                         keyCode = CAMKEY(DOWN);
02403                     else if ( current == wxT("HOME") )
02404                         keyCode = CAMKEY(HOME);
02405                     else if ( current == wxT("END") )
02406                         keyCode = CAMKEY(END);
02407                     else if ( current == wxT("SPACE") )
02408                         keyCode = CAMKEY(SPACE);
02409                     else if ( current == wxT("TAB") )
02410                         keyCode = CAMKEY(TAB);
02411                     else if ( current == wxT("ESC") || current == wxT("ESCAPE") )
02412                         keyCode = CAMKEY(ESCAPE);
02413                     else if ( current == wxT("CANCEL") )
02414                         keyCode = CAMKEY(CANCEL);
02415                     else if ( current == wxT("CLEAR") )
02416                         keyCode = CAMKEY(CLEAR);
02417                     else if ( current == wxT("MENU") )
02418                         keyCode = CAMKEY(MENU);
02419                     else if ( current == wxT("PAUSE") )
02420                         keyCode = CAMKEY(PAUSE);
02421                     else if ( current == wxT("CAPITAL") )
02422                         keyCode = CAMKEY(CAPITAL);
02423                     else if ( current == wxT("SELECT") )
02424                         keyCode = CAMKEY(SELECT);
02425                     else if ( current == wxT("PRINT") )
02426                         keyCode = CAMKEY(PRINT);
02427                     else if ( current == wxT("EXECUTE") )
02428                         keyCode = CAMKEY(EXECUTE);
02429                     else if ( current == wxT("SNAPSHOT") )
02430                         keyCode = CAMKEY(SNAPSHOT);
02431                     else if ( current == wxT("HELP") )
02432                         keyCode = CAMKEY(HELP);
02433                     else if ( current == wxT("ADD") )
02434                         keyCode = CAMKEY(ADD);
02435                     else if ( current == wxT("SEPARATOR") )
02436                         keyCode = CAMKEY(SEPARATOR);
02437                     else if ( current == wxT("SUBTRACT") )
02438                         keyCode = CAMKEY(SUBTRACT);
02439                     else if ( current == wxT("DECIMAL") )
02440                         keyCode = CAMKEY(DECIMAL);
02441                     else if ( current == wxT("DIVIDE") )
02442                         keyCode = CAMKEY(DIVIDE);
02443                     else if ( current == wxT("NUM_LOCK") )
02444                         keyCode = CAMKEY(NUMLOCK);
02445                     else if ( current == wxT("SCROLL_LOCK") )
02446                         keyCode = CAMKEY(SCROLL);
02447                     else if ( current == wxT("PAGEUP") )
02448                         keyCode = CAMKEY(PAGEUP);
02449                     else if ( current == wxT("PAGEDOWN") )
02450                         keyCode = CAMKEY(PAGEDOWN);
02451                     else if ( current == wxT("KP_SPACE") )
02452                         keyCode = CAMKEY(NUMPAD_SPACE);
02453                     else if ( current == wxT("KP_TAB") )
02454                         keyCode = CAMKEY(NUMPAD_TAB);
02455                     else if ( current == wxT("KP_ENTER") )
02456                         keyCode = CAMKEY(NUMPAD_ENTER);
02457                     else if ( current == wxT("KP_HOME") )
02458                         keyCode = CAMKEY(NUMPAD_HOME);
02459                     else if ( current == wxT("KP_LEFT") )
02460                         keyCode = CAMKEY(NUMPAD_LEFT);
02461                     else if ( current == wxT("KP_UP") )
02462                         keyCode = CAMKEY(NUMPAD_UP);
02463                     else if ( current == wxT("KP_RIGHT") )
02464                         keyCode = CAMKEY(NUMPAD_RIGHT);
02465                     else if ( current == wxT("KP_DOWN") )
02466                         keyCode = CAMKEY(NUMPAD_DOWN);
02467                     else if ( current == wxT("KP_PRIOR") )
02468                         keyCode = CAMKEY(NUMPAD_PRIOR);
02469                     else if ( current == wxT("KP_PAGEUP") )
02470                         keyCode = CAMKEY(NUMPAD_PAGEUP);
02471                     else if ( current == wxT("KP_NEXT;") )
02472                         keyCode = CAMKEY(NUMPAD_NEXT);
02473                     else if ( current == wxT("KP_PAGEDOWN") )
02474                         keyCode = CAMKEY(NUMPAD_PAGEDOWN);
02475                     else if ( current == wxT("KP_END") )
02476                         keyCode = CAMKEY(NUMPAD_END);
02477                     else if ( current == wxT("KP_BEGIN") )
02478                         keyCode = CAMKEY(NUMPAD_BEGIN);
02479                     else if ( current == wxT("KP_INSERT") )
02480                         keyCode = CAMKEY(NUMPAD_INSERT);
02481                     else if ( current == wxT("KP_DELETE") )
02482                         keyCode = CAMKEY(NUMPAD_DELETE);
02483                     else if ( current == wxT("KP_EQUAL") )
02484                         keyCode = CAMKEY(NUMPAD_EQUAL);
02485                     else if ( current == wxT("KP_MULTIPLY") ||
02486                               current == wxT("*") && bNumPad )
02487                         keyCode = CAMKEY(NUMPAD_MULTIPLY);
02488                     else if ( current == wxT("KP_ADD") ||
02489                               current == wxT("+") && bNumPad )
02490                         keyCode = CAMKEY(NUMPAD_ADD);
02491                     else if ( current == wxT("KP_SEPARATOR") )
02492                         keyCode = CAMKEY(NUMPAD_SEPARATOR);
02493                     else if ( current == wxT("KP_SUBTRACT") ||
02494                               current == wxT("-") && bNumPad )
02495                         keyCode = CAMKEY(NUMPAD_SUBTRACT);
02496                     else if ( current == wxT("KP_DECIMAL") ||
02497                               current == wxT(".") && bNumPad )
02498                         keyCode = CAMKEY(NUMPAD_DECIMAL);
02499                     else if ( current == wxT("KP_DIVIDE") ||
02500                               current == wxT("/") && bNumPad )
02501                         keyCode = CAMKEY(NUMPAD_DIVIDE);
02502                     else if ( current == wxT("WINDOWS_LEFT") )
02503                         keyCode = CAMKEY(WINDOWS_LEFT);
02504                     else if ( current == wxT("WINDOWS_RIGHT") )
02505                         keyCode = CAMKEY(WINDOWS_RIGHT);
02506                     else if ( current == wxT("WINDOWS_MENU") )
02507                         keyCode = CAMKEY(WINDOWS_MENU);
02508                     else if ( current == wxT("COMMAND") )
02509                         keyCode = CAMKEY(COMMAND);
02510                     else if ( bNumPad && current.Len()==1 && wxIsdigit(current[0U]) )
02511                         keyCode = CAMKEY(NUMPAD0) + wxAtoi(current.c_str());
02512                     else if ( current.Left(3) == wxT("KP_") && wxIsdigit(current[3U]) )
02513                         keyCode = CAMKEY(NUMPAD0) + wxAtoi(current.c_str() + 3);
02514                     else if ( current.Left(7) == wxT("SPECIAL") && wxIsdigit(current[7U]) )
02515                         keyCode = CAMKEY(SPECIAL1) + wxAtoi(current.c_str() + 7) - 1;
02516                     else
02517                     {
02518                         wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
02519                                    current.c_str());
02520                         return NULL;
02521                     }
02522                 }
02523             }
02524         }
02525 
02526         if ( keyCode ) {
02527             // we do have something
02528             return new wxAcceleratorEntry(accelFlags, keyCode);
02529         }
02530     }
02531 
02532     return (wxAcceleratorEntry *)NULL;
02533 }
02534 
02535 #endif
02536 
02538 
02539 
02540 
02541 
02542 
02543 /*********************************************************************************************
02544 >   void CCamApp::OnFatalException()
02545 
02546     Author:     Alex Bligh <alex@alex.org.uk>
02547     Created:    09/05/06
02548     Inputs:     -
02549     Outputs:    -
02550     Returns:    -
02551     Purpose:    This function is called whenever a fatal exception has occurred
02552     Errors:     -
02553     Scope:      Public
02554     SeeAlso:    -
02555 
02556 **********************************************************************************************/ 
02557 
02558 void CCamApp::OnFatalException()
02559 {
02560     static INT32 recursionguard = 0;
02561 
02562     if (recursionguard)
02563     {   
02564         // Oh dear, an error occurred whilst we had our box up. Exit immediately
02565         if (recursionguard++ > 1)
02566         {
02567             abort(); // do not even try to go through wx
02568             _exit(1); // how did we get here?
02569         }
02570 
02571         // switch fatal exception handling off
02572         ::wxHandleFatalExceptions(FALSE);
02573         TRACE(_T("CCamApp::OnFatalException() called recursively - dying now"));
02574         return; // this quits the app
02575     }
02576 
02577     recursionguard++;
02578 
02579     // Put this bit in a block so strings etc. allocated are deallocated before we go generate our own stack frame
02580     do
02581     {
02582         // Ensure we are reinstated as the signal handler
02583         ::wxHandleFatalExceptions(FALSE);
02584         ::wxHandleFatalExceptions(TRUE);
02585 
02586 // This bit of code is currently not operative - looking into wxDebugReport instead
02587 #ifdef EXCEPTION_LOCATION
02588         String_256 location(_R(IDS_DOOMUNKNOWN));
02589         // On platforms that support it, we try and find the appropriate error
02590 #if !defined(__WXMAC__) && !defined(__FreeBSD__)
02591 #define SWMAXLEVEL 200
02592         class StackWalker : public wxStackWalker
02593         {
02594         public:
02595             wxArrayString ArrayOfRefs;
02596             wxArrayString ArrayOfDetails;
02597             StackWalker() {ArrayOfRefs.SetCount(SWMAXLEVEL);ArrayOfDetails.SetCount(SWMAXLEVEL);}
02598             virtual void OnStackFrame(const wxStackFrame & frame)
02599             {
02600                 wxString details;
02601                 wxString fn=frame.GetFileName();
02602                 UINT32 line=frame.GetLine();
02603                 UINT32 level=frame.GetLevel();
02604                 details.Printf(_T("%d %s:%d %s"), level, fn.c_str(),
02605                             line, frame.GetName().c_str());
02606 #ifdef _DEBUG
02607                 wxLogDebug(details);
02608 #endif
02609                 if (level<SWMAXLEVEL)
02610                 {
02611                     ArrayOfDetails[level]=details;
02612                     details.Printf(_T("%s:%d"), fn.c_str(), line);
02613                     ArrayOfRefs[level]=details;
02614                 }
02615             }
02616         };
02617 
02618         TRACE(_T("Debug trace"));
02619         StackWalker s;
02620         s.Walk();
02621         // look 4 deep into the stack frame
02622         if (s.ArrayOfRefs[5].Length() >= 3)
02623             location=(const TCHAR *)(s.ArrayOfRefs[5]);
02624 #endif
02625 #endif
02626 
02627         DisableSystem();
02628     
02629         Progress::Smash(TRUE); // smash the progress bar
02630         
02631         // Relase the mouse if captured
02632         wxWindow *pCapture=wxWindow::GetCapture();
02633         if (pCapture)
02634             pCapture->ReleaseMouse();
02635     
02636         if (Error::ErrorBoxRecurse)
02637         {
02638             INT32 result=wxYES;
02639 
02640             // We're in an error box - don't ask the error system to put up the box, do it manually
02641             if (InInitOrDeInit)
02642             {
02643             // We'll try and get the string for the message box from resources. If the resource system is dead,
02644                 // they won't be able to carry on working anyway.
02645                 String_256 PortentOfDoom(_R(IDS_DOOMMESSAGE2));
02646                 String_256 TitleOfDoom(_R(IDS_DOOMTITLE));
02647                 result = ::wxMessageBox(wxString((TCHAR *)PortentOfDoom), wxString((TCHAR *)TitleOfDoom), wxICON_ERROR); // this will be wxOK, not wxYES
02648             }
02649             else
02650             {
02651                 // We'll try and get the string for the message box from resources. If the resource system is dead,
02652                 // they won't be able to carry on working anyway.
02653                 String_256 PortentOfDoom(_R(IDS_DOOMMESSAGE));
02654                 String_256 TitleOfDoom(_R(IDS_DOOMTITLE));
02655                 result = ::wxMessageBox(wxString((TCHAR *)PortentOfDoom), wxString((TCHAR *)TitleOfDoom), wxICON_ERROR | wxYES_NO);
02656             }
02657         
02658             if (InInitOrDeInit || (result != wxYES))
02659             {
02660                 recursionguard--;
02661                 return; // drop back into exception handler so as to quit.
02662             }
02663         }
02664         else
02665         {
02666             // Use InformGeneral - this gives us the chance to produce a debug report
02667             BOOL Quit=TRUE;
02668 
02669             if (InInitOrDeInit)
02670                 Quit = ::InformGeneral(ERRORTYPE_SERIOUS, 0, _R(IDS_DOOMMESSAGE2),
02671                                         _R(IDS_DOOMQUITNOW), 0, 0, 0,
02672                                         1, 1);
02673             else
02674                 Quit = (::InformGeneral(ERRORTYPE_SERIOUS, 0, _R(IDS_DOOMMESSAGE),
02675                                         _R(IDS_DOOMSAVEWORK), _R(IDS_DOOMQUITNOW), 0, 0,
02676                                         1, 1) != 1);
02677 
02678             if (InInitOrDeInit || Quit)
02679             {
02680                 recursionguard--;
02681                 return; // drop back into exception handler so as to quit.
02682             }
02683         }
02684 
02685     
02686         if ( Error::IsInRenderThread() )
02687         {
02688             TRACE( _T("In RenderThread so clearing up system"));
02689             Error::RenderThreadReset();
02690             CamProfile::AtBase(CAMPROFILE_OTHER);
02691         }
02692     
02693         GBrush::ResetOnFatalError(); // this clears an annoying ensure
02694     
02695         if (IsDisabled()) // Error box routines can enable it
02696             EnableSystem();
02697 
02698         recursionguard--;
02699     
02700         // Zap out main loop pointer
02701 #if !defined(__WXMAC__)
02702         m_mainLoop=NULL;
02703 #endif
02704 
02705     } while(0);
02706     
02707     // We'd like to jump back into the main loop. We can't throw() as allegedly this doesn't work through
02708     // gtk's stack frames (being C not C++) on some compilers sometimes. And destroying things might
02709     // be bad. We don't do setjmp/longjmp as that would leave objects on the stack in a state where they
02710     // are allocated but would be trampled on. So what we do is run another stack frame inside ourselves
02711     // which is a little nasty. We simulate the wx event loop from wxEntryReal.
02712     // Do not return, as this will do an abort().
02713     exit(RunFalseMainLoop());
02714 }
02715 
02716 /*********************************************************************************************
02717 >   INT32 CCamApp::RunFalseMainLoop()
02718 
02719     Author:     Alex Bligh <alex@alex.org.uk>
02720     Created:    09/05/06
02721     Inputs:     -
02722     Outputs:    -
02723     Returns:    -
02724     Purpose:    This function runs a false "main" loop, doing exit clean up etc. where
02725                 possible - See CCamApp::OnFatalException() for how it works
02726     Errors:     -
02727     Scope:      Public
02728     SeeAlso:    -
02729 
02730 We assume that app initialization has already been done, or we wouldn't have been installed
02731 as the exception handler. So we don't do it again. Note we return from this (so the OnExit()
02732 stuff gets called), but that the caller should then exit() immediately.
02733 
02734 **********************************************************************************************/ 
02735 
02736 static inline void Use(void *) {}
02737 
02738 INT32 CCamApp::RunFalseMainLoop()
02739 {
02740     class cleanupOnExit
02741     {
02742     public:
02743         ~cleanupOnExit() { wxEntryCleanup(); }
02744     } cleanupOnExit;
02745 
02746     Use(&cleanupOnExit); // suppress warning
02747 
02748     wxTRY
02749     {
02750         // ensure that OnExit() is called if OnInit() had succeeded
02751         class CallOnExit
02752         {
02753         public:
02754             ~CallOnExit() { wxTheApp->OnExit(); }
02755         } callOnExit;
02756 
02757         Use(&callOnExit); // suppress warning
02758 
02759         // app execution
02760         return wxTheApp->OnRun();
02761     }
02762     wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; )
02763 }
02764 
02765 
02771 class CMediaReplayDetect
02772 {
02773 private:
02774     wxArrayString       m_astrPathElement;
02775 
02776 public:
02777     CMediaReplayDetect()
02778     {
02779         wxString        strPath;
02780         wxGetEnv( _T("PATH"), &strPath );
02781 
02782         while( strPath != _T("") )
02783         {
02784             INT32           ordSep = strPath.Find( _T(':') );
02785             if( -1 == ordSep )
02786             {
02787                 if( strPath.Len() > 0 )
02788                     m_astrPathElement.Add( strPath );
02789                 break;
02790             }
02791 
02792             m_astrPathElement.Add( strPath.Mid( 0, ordSep ) );
02793             TRACEUSER( "jlh92", _T("Add ele %s\n"), PCTSTR(strPath.Mid( 0, ordSep )) );
02794             strPath = strPath.Mid( ordSep + 1 );
02795         }
02796     }
02797 
02798     bool IsAppPresent( const wxString& strApp )
02799     {
02800         size_t          cElement = m_astrPathElement.GetCount();
02801         for( size_t ord = 0; ord < cElement; ++ord )
02802         {
02803             wxString    strFullPath = m_astrPathElement.Item( ord );
02804             strFullPath += _T("/");
02805             strFullPath += strApp;
02806 
02807             if( wxFile::Exists( strFullPath ) )
02808                 return true;
02809         }
02810 
02811         return false;
02812     }
02813 };
02814 
02815 /*********************************************************************************************
02816 >   static void FillMediaAppMap( SelMediaDlgParam::CMediaAppList* pMapMediaApp )
02817 
02818     Author:     Luke_Hart (Xara Group Ltd) <camelotdev@xara.com> <luke.hartΩxara.com>
02819     Created:    23/08/06
02820     Inputs:     pMapMediaApp - A map to contain all the media apps avaiable on system
02821     Outputs:    -
02822     Returns:    -
02823     Purpose:    Retrieve a map of media replay applications
02824     Errors:     -
02825     Scope:      Public
02826     SeeAlso:    -
02827 
02828  **********************************************************************************************/
02829 
02830 static PCTSTR           g_apszApps[] = {_T("mplayer"),
02831                                         _T("gmplayer"),
02832                                         PCTSTR(1),              // Everyting above this line supports mplayer control protocol
02833                                         _T("gxine"),
02834                                         _T("xine"),
02835                                         _T("totem"),
02836                                         _T("xfmedia"),
02837                                         _T("codeine"),
02838                                         NULL };
02839 
02840 static void FillMediaAppMap( SelMediaDlgParam::CMediaAppList* pMapMediaApp )
02841 {
02842     // Add the basic list of applications
02843     bool                fControlable = true;
02844     UINT32              ord = 0;
02845     while( NULL != g_apszApps[ord] )
02846     {
02847         // Skip controlable marker
02848         if( PCTSTR(1) == g_apszApps[ord] )
02849         {
02850             ++ord;
02851             fControlable = false;
02852             continue;
02853         }
02854 
02855         pMapMediaApp->insert( std::make_pair( g_apszApps[ord], fControlable ) );
02856         ++ord;
02857     }
02858 
02859     // Remove any non-present apps
02860     CMediaReplayDetect  Detect;
02861     SelMediaDlgParam::CMediaAppListIter end( pMapMediaApp->end() );
02862     SelMediaDlgParam::CMediaAppListIter iter( pMapMediaApp->begin() );
02863     for( ; iter != end; )
02864     {
02865         SelMediaDlgParam::CMediaAppListIter iterCur( iter++ ); 
02866         if( !Detect.IsAppPresent( iterCur->first ) )
02867         {
02868             TRACEUSER( "luke", _T("%s is not present"), (PCTSTR)iterCur->first );
02869              pMapMediaApp->erase( iterCur->first );
02870         }
02871     }
02872 }
02873 
02874 
02875 /*********************************************************************************************
02876 >   bool CCamApp::LaunchMediaApp( const wxString& strUrl )
02877 
02878     Author:     Luke_Hart (Xara Group Ltd) <camelotdev@xara.com> <luke.hartΩxara.com>
02879     Created:    23/08/06
02880     Inputs:     strUrl - The path to the file conbtaining the movie to play (could even be 
02881                             web address)
02882     Outputs:    -
02883     Returns:    true if player launched successfully
02884     Purpose:    This function attempts to replay a movie using configured player (or ask user 
02885                 to specify one if not already setup)
02886     Errors:     -
02887     Scope:      Public
02888     SeeAlso:    -
02889 
02890  **********************************************************************************************/
02891 
02892 bool CCamApp::LaunchMediaApp( const wxString& strUrl )
02893 {
02894     // Move array into a helpful structure
02895     SelMediaDlgParam::CMediaAppList mapMediaApp;
02896     FillMediaAppMap( &mapMediaApp );
02897 
02898     // First we see if the replay app. is present
02899     CMediaReplayDetect  Detect;
02900     if( !Detect.IsAppPresent( m_strMediaApplication ) )
02901     {
02902         // Setup param and open replay app selection dialog
02903         SelMediaDlgParam    Param;
02904         Param.m_pAppList = &mapMediaApp;
02905         OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor( CC_RUNTIME_CLASS(SelMediaDlg) ); 
02906         if( NULL != pOpDesc )
02907         {
02908             pOpDesc->Invoke( &Param );
02909         
02910             if( Param.m_fValid )
02911                 m_strMediaApplication = Param.m_strSel;
02912         }
02913 
02914         // User canceled, bomb out
02915         if( !Param.m_fValid )
02916             return true;
02917     }
02918 
02919     // Check to see if we can control the selected app. (maybe one day....)
02920     SelMediaDlgParam::CMediaAppListIter iter = mapMediaApp.find( (PCTSTR)m_strMediaApplication );
02921     bool                fMPlayer = false;
02922     if( mapMediaApp.end() != iter )
02923         fMPlayer = iter->second;
02924 
02925     // Build the command line and execute it
02926     wxString            strCommand;
02927     strCommand = PCTSTR(m_strMediaApplication);
02928     if( fMPlayer )
02929         strCommand.append( _T(" -quiet ") );
02930     strCommand.Append( _T(" \"") );
02931     strCommand.Append( strUrl );
02932     strCommand.Append( _T("\"") );
02933 
02934     CamLaunchProcess*   plp = new CamLaunchProcess();
02935     if (plp==NULL)
02936         return false;
02937 
02938     bool                ok = FALSE != plp->Execute( strCommand );
02939     if (ok)
02940     {
02941         // Let this process run free!
02942         plp->Disconnect();
02943     }
02944     else
02945     {
02946         // Make sure we don't leave any zombie processes lying around
02947         wxKillError e = plp->Terminate();       // This should result in a call to OnTerminate
02948         TRACEUSER("Phil", _T("Terminating bad process returned %d\n"), e);
02949     }
02950 
02951     return ok;
02952 }
02953 
02954 /*********************************************************************************************
02955 >   bool CCamApp::SelectMediaApp()
02956 
02957     Author:     Luke_Hart (Xara Group Ltd) <camelotdev@xara.com> <luke.hartΩxara.com>
02958     Created:    23/08/06
02959     Inputs:     -
02960     Outputs:    -
02961     Returns:    true if user accepts new choice
02962     Purpose:    This function allows a user to select which media replay app. they'd like
02963                 to use to replay the help movies
02964     Errors:     -
02965     Scope:      Public
02966     SeeAlso:    -
02967 
02968  **********************************************************************************************/ 
02969 
02970 bool CCamApp::SelectMediaApp()
02971 {
02972     // Move array into a helpful structure
02973     SelMediaDlgParam::CMediaAppList mapMediaApp;
02974     FillMediaAppMap( &mapMediaApp );
02975 
02976     // First we see if the replay app. is present
02977     CMediaReplayDetect  Detect;
02978 
02979     // Setup param and open replay app selection dialog
02980     SelMediaDlgParam    Param;
02981     Param.m_pAppList = &mapMediaApp;
02982     Param.m_strSel   = m_strMediaApplication;
02983     OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor( CC_RUNTIME_CLASS(SelMediaDlg) ); 
02984     if( NULL != pOpDesc )
02985     {
02986         pOpDesc->Invoke( &Param );
02987     
02988         if( Param.m_fValid )
02989             m_strMediaApplication = Param.m_strSel;
02990     }
02991 
02992     // User canceled, bomb out
02993     return Param.m_fValid;
02994 }
02995 

Generated on Sat Nov 10 03:48:08 2007 for Camelot by  doxygen 1.4.4