2006-01-16 22:02:54 +01:00
// Copyright (c) 2005, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
////////////
// Includes
# include <wx/wxprec.h>
# include <wx/config.h>
# include <wx/filename.h>
# include <wx/msgdlg.h>
2007-01-07 23:54:04 +01:00
# include <wx/mimetype.h>
2007-04-13 02:04:44 +02:00
# include <wx/utils.h>
2007-06-21 02:46:50 +02:00
# include <wx/stdpaths.h>
2007-06-21 08:52:15 +02:00
# include <wx/filefn.h>
2007-12-31 07:46:22 +01:00
# include "config.h"
2006-01-16 22:02:54 +01:00
# include "main.h"
# include "frame_main.h"
# include "options.h"
# include "hotkeys.h"
# include "dialog_associations.h"
# include "ass_file.h"
# include "audio_box.h"
# include "audio_display.h"
# include "export_framerate.h"
# include "ass_export_filter.h"
# include "ass_time.h"
2006-02-27 05:18:00 +01:00
# include "ass_dialogue.h"
2006-02-18 22:55:58 +01:00
# include "subs_grid.h"
2007-01-15 07:56:35 +01:00
# include "subtitle_format.h"
2007-01-21 07:30:19 +01:00
# include "video_context.h"
2007-06-21 02:46:50 +02:00
# include "standard_paths.h"
2007-12-31 07:46:22 +01:00
# ifdef WITH_AUTOMATION
# include "auto4_base.h"
# endif
2006-01-16 22:02:54 +01:00
///////////////////
// wxWidgets macro
IMPLEMENT_APP ( AegisubApp )
2007-07-05 21:11:54 +02:00
#if 0
void StartupLog ( const wxString & msg ) {
static wxStopWatch clock ;
wxString nmsg = wxString : : Format ( _T ( " Startup: %d - %s \n " ) , clock . Time ( ) , msg . c_str ( ) ) ;
# ifdef WIN32
OutputDebugStringW ( nmsg . wc_str ( ) ) ;
# else
printf ( nmsg . mb_str ( wxConvLocal ) ) ;
# endif
}
# else
# define StartupLog(a)
# endif
2006-01-16 22:02:54 +01:00
///////////////////////////
// Initialization function
// -----------------------
// Gets called when application starts, creates MainFrame
bool AegisubApp : : OnInit ( ) {
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Inside OnInit " ) ) ;
2006-01-16 22:02:54 +01:00
try {
// Initialize randomizer
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Initialize random generator " ) ) ;
2006-01-16 22:02:54 +01:00
srand ( time ( NULL ) ) ;
2007-04-03 06:34:56 +02:00
// locale for loading options
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Set initial locale " ) ) ;
2007-04-03 06:34:56 +02:00
setlocale ( LC_NUMERIC , " C " ) ;
setlocale ( LC_CTYPE , " C " ) ;
2007-07-01 02:19:55 +02:00
// App name (yeah, this is a little weird to get rid of an odd warning)
# ifdef __WXMSW__
SetAppName ( _T ( " Aegisub " ) ) ;
# else
# ifdef __WXMAC__
2006-01-16 22:02:54 +01:00
SetAppName ( _T ( " Aegisub " ) ) ;
2007-06-22 05:14:25 +02:00
# else
SetAppName ( _T ( " aegisub " ) ) ;
2007-07-01 02:19:55 +02:00
# endif
2007-06-22 05:14:25 +02:00
# endif
// Crash handling
2007-07-01 02:19:55 +02:00
# ifndef _DEBUG
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Install exception handler " ) ) ;
2006-01-16 22:02:54 +01:00
wxHandleFatalExceptions ( true ) ;
2007-07-01 02:19:55 +02:00
# endif
2006-01-16 22:02:54 +01:00
// Set config file
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Load configuration " ) ) ;
2007-06-21 08:14:49 +02:00
Options . SetFile ( StandardPaths : : DecodePath ( _T ( " ?data/config.dat " ) ) ) ;
2007-06-21 08:52:15 +02:00
Options . LoadDefaults ( ) ;
2006-01-16 22:02:54 +01:00
Options . Load ( ) ;
2007-06-21 08:14:49 +02:00
if ( ! Options . AsBool ( _T ( " Local config " ) ) ) {
Options . SetFile ( StandardPaths : : DecodePath ( _T ( " ?user/config.dat " ) ) ) ;
Options . Load ( ) ;
2007-06-21 08:52:15 +02:00
wxRemoveFile ( StandardPaths : : DecodePath ( _T ( " ?data/config.dat " ) ) ) ;
2007-06-21 08:14:49 +02:00
}
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Store options back " ) ) ;
2007-06-21 08:14:49 +02:00
Options . Save ( ) ;
2006-01-16 22:02:54 +01:00
AssTime : : UseMSPrecision = Options . AsBool ( _T ( " Use nonstandard Milisecond Times " ) ) ;
// Set hotkeys file
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Load hotkeys " ) ) ;
2007-06-21 02:46:50 +02:00
Hotkeys . SetFile ( StandardPaths : : DecodePath ( _T ( " ?user/hotkeys.dat " ) ) ) ;
2006-01-16 22:02:54 +01:00
Hotkeys . Load ( ) ;
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Initialize final locale " ) ) ;
2006-05-10 02:33:44 +02:00
# ifdef __WINDOWS__
2006-01-16 22:02:54 +01:00
// Set locale
int lang = Options . AsInt ( _T ( " Locale Code " ) ) ;
if ( lang = = - 1 ) {
lang = locale . PickLanguage ( ) ;
Options . SetInt ( _T ( " Locale Code " ) , lang ) ;
Options . Save ( ) ;
}
locale . Init ( lang ) ;
2006-05-06 16:38:53 +02:00
# else
2007-04-03 06:34:56 +02:00
locale . Init ( wxLANGUAGE_DEFAULT ) ;
2006-05-06 16:38:53 +02:00
# endif
2006-01-16 22:02:54 +01:00
2007-04-22 17:45:29 +02:00
// Set association
# ifndef _DEBUG
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Install file type associations " ) ) ;
2007-04-22 17:45:29 +02:00
RegistryAssociate ( ) ;
# endif
2006-12-28 23:31:33 +01:00
// Load Automation scripts
2007-12-31 07:46:22 +01:00
# ifdef WITH_AUTOMATION
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Load global Automation scripts " ) ) ;
2006-12-28 23:31:33 +01:00
global_scripts = new Automation4 : : AutoloadScriptManager ( Options . AsText ( _T ( " Automation Autoload Path " ) ) ) ;
2007-12-31 07:46:22 +01:00
# endif
2006-12-28 23:31:33 +01:00
2006-01-16 22:02:54 +01:00
// Load export filters
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Prepare export filters " ) ) ;
2006-01-16 22:02:54 +01:00
AssExportFilterChain : : PrepareFilters ( ) ;
// Get parameter subs
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Parse command line " ) ) ;
2006-01-16 22:02:54 +01:00
wxArrayString subs ;
for ( int i = 1 ; i < argc ; i + + ) {
subs . Add ( argv [ i ] ) ;
}
// Open main frame
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Create main window " ) ) ;
2006-01-16 22:02:54 +01:00
frame = new FrameMain ( subs ) ;
SetTopWindow ( frame ) ;
}
2006-04-14 18:46:38 +02:00
catch ( const wchar_t * err ) {
2006-01-16 22:02:54 +01:00
wxMessageBox ( err , _T ( " Fatal error while initializing " ) ) ;
return false ;
}
catch ( . . . ) {
wxMessageBox ( _T ( " Unhandled exception " ) , _T ( " Fatal error while initializing " ) ) ;
return false ;
}
2007-07-05 21:11:54 +02:00
StartupLog ( _T ( " Initialization complete " ) ) ;
2006-01-16 22:02:54 +01:00
return true ;
}
2007-01-15 06:38:32 +01:00
////////
// Exit
int AegisubApp : : OnExit ( ) {
2007-01-15 07:56:35 +01:00
SubtitleFormat : : DestroyFormats ( ) ;
2007-01-21 07:30:19 +01:00
VideoContext : : Clear ( ) ;
2007-01-15 06:38:32 +01:00
Options . Clear ( ) ;
2007-12-31 07:46:22 +01:00
# ifdef WITH_AUTOMATION
2007-01-15 07:56:35 +01:00
delete global_scripts ;
2007-12-31 07:46:22 +01:00
# endif
2007-01-15 06:38:32 +01:00
return wxApp : : OnExit ( ) ;
}
2006-02-26 23:45:34 +01:00
# ifndef _DEBUG
2006-01-16 22:02:54 +01:00
///////////////////////
// Unhandled exception
void AegisubApp : : OnUnhandledException ( ) {
2006-02-21 06:26:13 +01:00
// Attempt to recover file
2006-07-07 01:20:30 +02:00
wxFileName origfile ( AssFile : : top - > filename ) ;
wxString path = Options . AsText ( _T ( " Auto recovery path " ) ) ;
2007-06-21 04:38:04 +02:00
if ( path . IsEmpty ( ) ) path = StandardPaths : : DecodePath ( _T ( " ?user/ " ) ) ;
2006-07-07 01:20:30 +02:00
wxFileName dstpath ( path ) ;
2007-06-21 04:38:04 +02:00
if ( ! dstpath . IsAbsolute ( ) ) path = StandardPaths : : DecodePath ( _T ( " ?user/ " ) ) + path ;
2006-07-07 01:20:30 +02:00
path + = _T ( " / " ) ;
dstpath . Assign ( path ) ;
if ( ! dstpath . DirExists ( ) ) wxMkdir ( path ) ;
2007-06-21 04:38:04 +02:00
wxString filename = StandardPaths : : DecodePath ( _T ( " ?user/ " ) ) + origfile . GetName ( ) + _T ( " .RECOVER.ass " ) ;
2006-01-16 22:02:54 +01:00
AssFile : : top - > Save ( filename , false , false ) ;
2006-02-21 06:26:13 +01:00
// Inform user of crash
2006-01-16 22:02:54 +01:00
wxMessageBox ( _T ( " Aegisub has encountered an unhandled exception error and will terminate now. The subtitles you were working on were saved to \" " ) + filename + _T ( " \" , but they might be corrupt. " ) , _T ( " Unhandled exception " ) , wxOK | wxICON_ERROR , NULL ) ;
}
///////////////////
// Fatal exception
void AegisubApp : : OnFatalException ( ) {
2006-02-21 06:26:13 +01:00
// Attempt to recover file
2006-07-07 01:20:30 +02:00
wxFileName origfile ( AssFile : : top - > filename ) ;
wxString path = Options . AsText ( _T ( " Auto recovery path " ) ) ;
2007-06-21 04:38:04 +02:00
if ( path . IsEmpty ( ) ) path = StandardPaths : : DecodePath ( _T ( " ?user/ " ) ) ;
2006-07-07 01:20:30 +02:00
wxFileName dstpath ( path ) ;
2007-06-21 04:38:04 +02:00
if ( ! dstpath . IsAbsolute ( ) ) path = StandardPaths : : DecodePath ( _T ( " ?user/ " ) ) + path ;
2006-07-07 01:20:30 +02:00
path + = _T ( " / " ) ;
dstpath . Assign ( path ) ;
if ( ! dstpath . DirExists ( ) ) wxMkdir ( path ) ;
wxString filename = path + origfile . GetName ( ) + _T ( " .RECOVER.ass " ) ;
2006-01-16 22:02:54 +01:00
AssFile : : top - > Save ( filename , false , false ) ;
2006-02-21 06:26:13 +01:00
// Stack walk
2006-04-13 09:09:27 +02:00
# if wxUSE_STACKWALKER == 1
2006-02-21 06:26:13 +01:00
StackWalker walker ;
walker . WalkFromException ( ) ;
2006-04-13 09:09:27 +02:00
# endif
2006-02-21 06:26:13 +01:00
// Inform user of crash
wxMessageBox ( _T ( " Aegisub has encountered a fatal error and will terminate now. The subtitles you were working on were saved to \" " ) + filename + _T ( " \" , but they might be corrupt. " ) , _T ( " Fatal error " ) , wxOK | wxICON_ERROR , NULL ) ;
}
2006-02-26 23:45:34 +01:00
# endif
2006-02-21 06:26:13 +01:00
////////////////
// Stack walker
2006-04-13 09:09:27 +02:00
# if wxUSE_STACKWALKER == 1
2006-02-21 06:26:13 +01:00
void StackWalker : : OnStackFrame ( const wxStackFrame & frame ) {
wxString dst = wxString : : Format ( _T ( " %03i - 0x%08X: " ) , frame . GetLevel ( ) , frame . GetAddress ( ) ) + frame . GetName ( ) + _T ( " on " ) + frame . GetFileName ( ) + wxString : : Format ( _T ( " :%i " ) , frame . GetLine ( ) ) ;
char temp [ 2048 ] ;
if ( file . is_open ( ) ) {
strcpy ( temp , dst . mb_str ( ) ) ;
file < < temp < < std : : endl ;
}
else wxLogMessage ( dst ) ;
}
StackWalker : : StackWalker ( ) {
2007-07-23 23:46:56 +02:00
file . open ( wxString ( StandardPaths : : DecodePath ( _T ( " ?user/crashlog.txt " ) ) ) . mb_str ( ) , std : : ios : : out | std : : ios : : app ) ;
2006-02-21 06:26:13 +01:00
if ( file . is_open ( ) ) {
file < < std : : endl < < " Begining stack dump: \n " ;
}
}
StackWalker : : ~ StackWalker ( ) {
if ( file . is_open ( ) ) {
file < < " End of stack dump. \n \n " ;
file . close ( ) ;
}
2006-01-16 22:02:54 +01:00
}
2006-04-13 09:09:27 +02:00
# endif
2006-01-16 22:02:54 +01:00
//////////////////
// Call main loop
int AegisubApp : : OnRun ( ) {
try {
if ( m_exitOnFrameDelete = = Later ) m_exitOnFrameDelete = Yes ;
return MainLoop ( ) ;
}
catch ( wxString err ) {
wxMessageBox ( err , _T ( " Unhandled exception " ) , wxOK | wxICON_ERROR , NULL ) ;
}
2006-02-20 08:12:01 +01:00
catch ( wxChar * error ) {
wxMessageBox ( error , _T ( " Unhandled exception " ) , wxOK | wxICON_ERROR , NULL ) ;
}
catch ( std : : exception e ) {
wxMessageBox ( wxString ( _T ( " std::exception: " ) ) + wxString ( e . what ( ) , wxConvUTF8 ) , _T ( " Unhandled exception " ) , wxOK | wxICON_ERROR , NULL ) ;
2006-01-16 22:02:54 +01:00
}
catch ( . . . ) {
wxMessageBox ( _T ( " Program terminated in error. " ) , _T ( " Unhandled exception " ) , wxOK | wxICON_ERROR , NULL ) ;
}
ExitMainLoop ( ) ;
return 1 ;
}
/////////////////////////////////
// Registry program to filetypes
void AegisubApp : : RegistryAssociate ( ) {
2007-04-13 03:54:47 +02:00
# if defined(__WINDOWS__)
2006-01-16 22:02:54 +01:00
// Command to open with this
wxString command ;
2007-06-21 02:46:50 +02:00
wxStandardPaths stand ;
wxString fullPath = stand . GetExecutablePath ( ) ;
command = _T ( " \" " ) + fullPath + _T ( " \" \" %1 \" " ) ;
2006-01-16 22:02:54 +01:00
// Main program association
2007-01-19 13:52:02 +01:00
wxRegKey * key = new wxRegKey ( _T ( " HKEY_CURRENT_USER \\ Software \\ Classes \\ Aegisub " ) ) ;
2006-01-16 22:02:54 +01:00
if ( ! key - > Exists ( ) ) key - > Create ( ) ;
key - > SetValue ( _T ( " " ) , _T ( " Aegisub Subtitle Script " ) ) ;
delete key ;
2007-01-19 13:52:02 +01:00
key = new wxRegKey ( _T ( " HKEY_CURRENT_USER \\ Software \\ Classes \\ Aegisub \\ DefaultIcon " ) ) ;
2006-01-16 22:02:54 +01:00
if ( ! key - > Exists ( ) ) key - > Create ( ) ;
2007-01-19 13:52:02 +01:00
key - > SetValue ( _T ( " " ) , fullPath ) ;
2006-01-16 22:02:54 +01:00
delete key ;
2007-01-19 13:52:02 +01:00
key = new wxRegKey ( _T ( " HKEY_CURRENT_USER \\ Software \\ Classes \\ Aegisub \\ Shell " ) ) ;
2006-01-16 22:02:54 +01:00
if ( ! key - > Exists ( ) ) key - > Create ( ) ;
2007-01-19 13:52:02 +01:00
key - > SetValue ( _T ( " " ) , _T ( " open " ) ) ;
2006-01-16 22:02:54 +01:00
delete key ;
2007-01-19 13:52:02 +01:00
key = new wxRegKey ( _T ( " HKEY_CURRENT_USER \\ Software \\ Classes \\ Aegisub \\ Shell \\ Open " ) ) ;
2006-01-16 22:02:54 +01:00
if ( ! key - > Exists ( ) ) key - > Create ( ) ;
2007-01-19 13:52:02 +01:00
key - > SetValue ( _T ( " " ) , _T ( " &Open with Aegisub " ) ) ;
2006-01-16 22:02:54 +01:00
delete key ;
2007-01-19 13:52:02 +01:00
key = new wxRegKey ( _T ( " HKEY_CURRENT_USER \\ Software \\ Classes \\ Aegisub \\ Shell \\ Open \\ Command " ) ) ;
2006-01-16 22:02:54 +01:00
if ( ! key - > Exists ( ) ) key - > Create ( ) ;
2007-01-19 13:52:02 +01:00
key - > SetValue ( _T ( " " ) , command ) ;
2006-01-16 22:02:54 +01:00
delete key ;
// Check associations
if ( Options . AsBool ( _T ( " Show associations " ) ) ) {
2007-06-19 06:04:46 +02:00
bool gotAll = DialogAssociations : : CheckAssociation ( _T ( " ass " ) ) & & DialogAssociations : : CheckAssociation ( _T ( " ssa " ) ) & &
DialogAssociations : : CheckAssociation ( _T ( " srt " ) ) & & DialogAssociations : : CheckAssociation ( _T ( " sub " ) ) & &
DialogAssociations : : CheckAssociation ( _T ( " ttxt " ) ) ;
2006-01-16 22:02:54 +01:00
if ( ! gotAll ) {
DialogAssociations diag ( NULL ) ;
diag . ShowModal ( ) ;
Options . SetBool ( _T ( " Show associations " ) , false ) ;
Options . Save ( ) ;
}
}
2007-04-13 03:54:47 +02:00
# elif defined(__APPLE__)
// This is totally untested and pure guesswork
// I don't know if it should be ".ass" or just "ass"
wxFileName : : MacRegisterDefaultTypeAndCreator ( _T ( " .ass " ) , 0x41535341 /*ASSA*/ , 0x41475355 /*AGSU*/ ) ;
// Technically .ssa isn't ASSA but it makes it so much easier ;)
wxFileName : : MacRegisterDefaultTypeAndCreator ( _T ( " .ssa " ) , 0x53534134 /*SSA4*/ , 0x41475355 /*AGSU*/ ) ;
// Not touching .srt yet, there might be some type already registered for it which we should probably use then
# else
// Is there anything like this for other POSIX compatible systems?
2006-01-16 22:02:54 +01:00
# endif
}
2007-01-07 23:54:04 +01:00
////////////
// Open URL
void AegisubApp : : OpenURL ( wxString url ) {
2007-04-13 02:04:44 +02:00
wxLaunchDefaultBrowser ( url , wxBROWSER_NEW_WINDOW ) ;
2007-01-07 23:54:04 +01:00
}
2006-06-19 04:57:27 +02:00
////////////////
// Apple events
# ifdef __WXMAC__
void AegisubApp : : MacOpenFile ( const wxString & filename ) {
if ( frame ! = NULL & & ! filename . empty ( ) ) {
frame - > LoadSubtitles ( filename ) ;
wxFileName filepath ( filename ) ;
Options . SetText ( _T ( " Last open subtitles path " ) , filepath . GetPath ( ) ) ;
}
}
# endif
2006-01-16 22:02:54 +01:00
///////////////
// Event table
BEGIN_EVENT_TABLE ( AegisubApp , wxApp )
EVT_MOUSEWHEEL ( AegisubApp : : OnMouseWheel )
EVT_KEY_DOWN ( AegisubApp : : OnKey )
END_EVENT_TABLE ( )
/////////////////////
// Mouse wheel moved
void AegisubApp : : OnMouseWheel ( wxMouseEvent & event ) {
wxPoint pt ;
wxWindow * target = wxFindWindowAtPointer ( pt ) ;
2006-02-18 22:55:58 +01:00
if ( target = = frame - > audioBox - > audioDisplay | | target = = frame - > SubsBox ) {
2007-07-03 03:09:39 +02:00
if ( target - > IsShownOnScreen ( ) ) target - > AddPendingEvent ( event ) ;
else event . Skip ( ) ;
2006-01-16 22:02:54 +01:00
}
else event . Skip ( ) ;
}
///////////////
// Key pressed
void AegisubApp : : OnKey ( wxKeyEvent & event ) {
2006-03-05 05:31:09 +01:00
//frame->audioBox->audioDisplay->AddPendingEvent(event);
2006-01-16 22:02:54 +01:00
if ( ! event . GetSkipped ( ) ) {
event . Skip ( ) ;
}
}