5 * Implementation of class HBOutputPanelController.
8 #import "HBOutputPanelController.h"
9 #import "HBOutputRedirect.h"
11 /// Maximum amount of characters that can be shown in the view.
12 // Original value used by cleaner
13 //#define TextStorageUpperSizeLimit 20000
14 // lets use this higher value for now for better gui debugging
15 #define TextStorageUpperSizeLimit 40000
17 /// When old output is removed, this is the amount of characters that will be
18 /// left in outputTextStorage.
19 // Original value used by cleaner
20 //#define TextStorageLowerSizeLimit 15000
21 // lets use this higher value for now for better gui debugging
22 #define TextStorageLowerSizeLimit 35000
24 @implementation HBOutputPanelController
27 * Initializes the object, creates outputTextStorage and starts redirection of stderr.
31 if( (self = [super initWithWindowNibName:@"OutputPanel"]) )
33 /* NSWindowController likes to lazily load its window nib. Since this
34 * controller tries to touch the outlets before accessing the window, we
35 * need to force it to load immadiately by invoking its accessor.
37 * If/when we switch to using bindings, this can probably go away.
41 /* We initialize the outputTextStorage object for the activity window */
42 outputTextStorage = [[NSTextStorage alloc] init];
44 /* We declare the default NSFileManager into fileManager */
45 NSFileManager * fileManager = [NSFileManager defaultManager];
46 /* Establish the log file location to write to */
47 /* We are initially using a .txt file as opposed to a .log file since it will open by
48 * default with the users text editor instead of the .log default Console.app, should
49 * create less confusion for less experienced users when we ask them to paste the log for support
51 outputLogFile = @"~/Library/Application Support/HandBrake/HandBrake-activitylog.txt";
52 outputLogFile = [[outputLogFile stringByExpandingTildeInPath]retain];
54 /* We check for an existing output log file here */
55 if( [fileManager fileExistsAtPath:outputLogFile] == 0 )
57 /* if not, then we create a new blank one */
58 [fileManager createFileAtPath:outputLogFile contents:nil attributes:nil];
60 /* We overwrite the existing output log with the date for starters the output log to start fresh with the new session */
61 /* Use the current date and time for the new output log header */
62 NSString *startOutputLogString = [NSString stringWithFormat: NSLocalizedStringFromTable(@"HandBrake Activity Log for Session (Cleared): %@\n\n", @"OutputPanel", @""), [[NSDate date] descriptionWithCalendarFormat:nil timeZone:nil locale:nil]];
63 [startOutputLogString writeToFile:outputLogFile atomically:YES encoding:NSUTF8StringEncoding error:NULL];
65 [[HBOutputRedirect stderrRedirect] addListener:self];
66 [[HBOutputRedirect stdoutRedirect] addListener:self];
68 [self setWindowFrameAutosaveName:@"OutputPanelFrame"];
69 [[textView layoutManager] replaceTextStorage:outputTextStorage];
70 [[textView enclosingScrollView] setLineScroll:10];
71 [[textView enclosingScrollView] setPageScroll:20];
79 * Stops redirection of stderr and releases resources.
83 [[HBOutputRedirect stderrRedirect] removeListener:self];
84 [[HBOutputRedirect stdoutRedirect] removeListener:self];
85 [outputTextStorage release];
90 * Loads output panel from OutputPanel.nib and shows it.
92 - (IBAction)showOutputPanel:(id)sender
94 if ([[self window] isVisible])
96 [[self window] close];
100 [textView scrollRangeToVisible:NSMakeRange([outputTextStorage length], 0)];
101 [self showWindow:sender];
103 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"OutputPanelIsOpen"];
107 - (void) startEncodeLog:(NSString *) logPath
110 NSString *outputFileForEncode = logPath ;
111 /* Since the destination path matches the extension of the output file, replace the
112 * output movie extension and replace it with ".txt"
114 NSFileManager * fileManager = [NSFileManager defaultManager];
115 /* Establish the log file location to write to */
116 /* We are initially using a .txt file as opposed to a .log file since it will open by
117 * default with the users text editor instead of the .log default Console.app, should
118 * create less confusion for less experienced users when we ask them to paste the log for support
120 /* We need to get the current time in YY-MM-DD HH-MM-SS format to put at the beginning of the name of the log file */
121 time_t _now = time( NULL );
122 struct tm * now = localtime( &_now );
123 NSString *dateForLogTitle = [NSString stringWithFormat:@"%02d-%02d-%02d %02d-%02d-%02d",now->tm_year + 1900, now->tm_mon + 1, now->tm_mday,now->tm_hour, now->tm_min, now->tm_sec];
125 /* Assemble the new log file name as YY-MM-DD HH-MM-SS mymoviename.txt */
126 NSString *outputDateFileName = [NSString stringWithFormat:@"%@ %@.txt",[[outputFileForEncode lastPathComponent] stringByDeletingPathExtension],dateForLogTitle];
127 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EncodeLogLocation"]) // if we are putting it in the same directory with the movie
130 outputLogFileForEncode = [[NSString stringWithFormat:@"%@/%@",[outputFileForEncode stringByDeletingLastPathComponent],outputDateFileName] retain];
132 else // if we are putting it in the default ~/Libraries/Application Support/HandBrake/EncodeLogs logs directory
134 NSString *libraryDir = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory,
136 YES ) objectAtIndex:0];
137 NSString *encodeLogDirectory = [[[libraryDir stringByAppendingPathComponent:@"Application Support"] stringByAppendingPathComponent:@"HandBrake"] stringByAppendingPathComponent:@"EncodeLogs"];
138 if( ![[NSFileManager defaultManager] fileExistsAtPath:encodeLogDirectory] )
140 [[NSFileManager defaultManager] createDirectoryAtPath:encodeLogDirectory
141 withIntermediateDirectories:NO
145 outputLogFileForEncode = [[NSString stringWithFormat:@"%@/%@",encodeLogDirectory,outputDateFileName] retain];
147 [fileManager createFileAtPath:outputLogFileForEncode contents:nil attributes:nil];
149 /* Similar to the regular activity log, we print a header containing the date and time of the encode as well as what directory it was encoded to */
151 NSString *versionStringFull = [[NSString stringWithFormat: NSLocalizedStringFromTable(@"Handbrake Version: %@", @"OutputPanel", @""), [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleGetInfoString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)\n\n", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
152 NSString *startOutputLogString = [NSString stringWithFormat: NSLocalizedStringFromTable(@"HandBrake Activity Log for %@: %@\n%@", @"OutputPanel", @""),outputFileForEncode, [[NSDate date] descriptionWithCalendarFormat:nil timeZone:nil locale:nil],versionStringFull];
154 NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)\n\n", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
155 NSString *startOutputLogString = [NSString stringWithFormat: @"HandBrake Activity Log for %@: %@\n%@",outputFileForEncode, [[NSDate date] descriptionWithCalendarFormat:nil timeZone:nil locale:nil],versionStringFull];
156 [startOutputLogString writeToFile:outputLogFileForEncode atomically:YES encoding:NSUTF8StringEncoding error:NULL];
161 - (void) endEncodeLog
167 * Displays text received from HBOutputRedirect in the text view.
169 - (void)stderrRedirect:(NSString *)text
172 NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:text];
173 /* Actually write the libhb output to the text view (outputTextStorage) */
174 [outputTextStorage appendAttributedString:attributedString];
175 [attributedString release];
177 /* remove text from outputTextStorage as defined by TextStorageUpperSizeLimit and TextStorageLowerSizeLimit */
178 if ([outputTextStorage length] > TextStorageUpperSizeLimit)
179 [outputTextStorage deleteCharactersInRange:NSMakeRange(0, [outputTextStorage length] - TextStorageLowerSizeLimit)];
181 [textView scrollRangeToVisible:NSMakeRange([outputTextStorage length], 0)];
183 /* We use a c function to write to the log file without reading it into memory
184 * as it should be faster and easier on memory than using cocoa's writeToFile
185 * thanks ritsuka !!*/
186 FILE *f = fopen([outputLogFile UTF8String], "a");
187 fprintf(f, "%s", [text UTF8String]);
190 if (encodeLogOn == YES && outputLogFileForEncode != nil)
192 FILE *e = fopen([outputLogFileForEncode UTF8String], "a");
193 fprintf(e, "%s", [text UTF8String]);
196 /* Below uses Objective-C to write to the file, though it is slow and uses
197 * more memory than the c function above. For now, leaving this in here
198 * just in case and commented out.
200 /* Put the new incoming string from libhb into an nsstring for appending to our log file */
201 //NSString *newOutputString = [[NSString alloc] initWithString:text];
202 /*get the current log file and put it into an NSString */
203 /* HACK ALERT: must be a way to do it without reading the whole log into memory
204 Performance note: could batch write to the log, but want to get each line as it comes out of
205 libhb in case of a crash or freeze so we see exactly what the last thing was before crash*/
206 //NSString *currentOutputLogString = [[NSString alloc]initWithContentsOfFile:outputLogFile encoding:NSUTF8StringEncoding error:NULL];
208 /* Append the new libhb output string to the existing log file string */
209 //currentOutputLogString = [currentOutputLogString stringByAppendingString:newOutputString];
210 /* Save the new modified log file string back to disk */
211 //[currentOutputLogString writeToFile:outputLogFile atomically:YES encoding:NSUTF8StringEncoding error:NULL];
212 /* Release the new libhb output string */
213 //[newOutputString release];
215 - (void)stdoutRedirect:(NSString *)text { [self stderrRedirect:text]; }
218 * Clears the output window.
220 - (IBAction)clearOutput:(id)sender
222 [outputTextStorage deleteCharactersInRange:NSMakeRange(0, [outputTextStorage length])];
223 /* We want to rewrite the app version info to the top of the activity window so it is always present */
225 NSString *versionStringFull = [[NSString stringWithFormat: NSLocalizedStringFromTable(@"Handbrake Version: %@", @"OutputPanel", @""), [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleGetInfoString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
227 NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)\n\n", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
228 time_t _now = time( NULL );
229 struct tm * now = localtime( &_now );
230 fprintf(stderr, "[%02d:%02d:%02d] macgui: %s\n", now->tm_hour, now->tm_min, now->tm_sec, [versionStringFull UTF8String]);
235 * Copies all text in the output window to pasteboard.
237 - (IBAction)copyAllOutputToPasteboard:(id)sender
239 NSPasteboard *pboard = [NSPasteboard generalPasteboard];
240 [pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
241 [pboard setString:[outputTextStorage string] forType:NSStringPboardType];
246 * Opens the activity log txt file in users default editor.
248 - (IBAction)openActivityLogFile:(id)sender
250 /* Opens the activity window log file in the users default text editor */
251 NSAppleScript *myScript = [[NSAppleScript alloc] initWithSource: [NSString stringWithFormat: @"%@%@%@", NSLocalizedStringFromTable(@"tell application \"Finder\" to open (POSIX file \"", @"OutputPanel", @""), outputLogFile, @"\")"]];
252 [myScript executeAndReturnError: nil];
257 * Opens the activity log txt file in users default editor.
259 - (IBAction)openEncodeLogDirectory:(id)sender
261 /* Opens the activity window log file in the users default text editor */
262 NSString *libraryDir = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory,
264 YES ) objectAtIndex:0];
265 NSString *encodeLogDirectory = [[[libraryDir stringByAppendingPathComponent:@"Application Support"] stringByAppendingPathComponent:@"HandBrake"] stringByAppendingPathComponent:@"EncodeLogs"];
266 if( ![[NSFileManager defaultManager] fileExistsAtPath:encodeLogDirectory] )
268 [[NSFileManager defaultManager] createDirectoryAtPath:encodeLogDirectory
269 withIntermediateDirectories:NO
274 NSAppleScript *myScript = [[NSAppleScript alloc] initWithSource: [NSString stringWithFormat: @"%@%@%@", NSLocalizedStringFromTable(@"tell application \"Finder\" to open (POSIX file \"", @"OutputPanel", @""), encodeLogDirectory, @"\")"]];
275 [myScript executeAndReturnError: nil];
279 - (IBAction)clearActivityLogFile:(id)sender
281 /* We overwrite the existing output log with the new date and time header */
282 /* Use the current date and time for the new output log header */
283 NSString *startOutputLogString = [NSString stringWithFormat: NSLocalizedStringFromTable(@"HandBrake Activity Log for Session Starting: %@\n\n", @"OutputPanel", @""), [[NSDate date] descriptionWithCalendarFormat:nil timeZone:nil locale:nil]];
284 [startOutputLogString writeToFile:outputLogFile atomically:NO encoding:NSUTF8StringEncoding error:NULL];
286 /* We want to rewrite the app version info to the top of the activity window so it is always present */
288 NSString *versionStringFull = [[NSString stringWithFormat: NSLocalizedStringFromTable(@"macgui: Handbrake Version: %@", @"OutputPanel", @""), [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleGetInfoString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
290 NSString *versionStringFull = [[NSString stringWithFormat: @"macgui: Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)\n\n", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
291 [versionStringFull writeToFile:outputLogFile atomically:NO encoding:NSUTF8StringEncoding error:NULL];
295 - (void)windowWillClose:(NSNotification *)aNotification
297 [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"OutputPanelIsOpen"];